diff options
author | jdike <jdike> | 2003-03-26 20:29:50 +0000 |
---|---|---|
committer | jdike <jdike> | 2003-03-26 20:29:50 +0000 |
commit | 9de5197b118e1c191434b59135fa89d66ed61479 (patch) | |
tree | d3da1916430d3043e24200fe8ba1fe4935f735e5 | |
parent | 180144c3992a88a8a4ab16bec2b2f9e1785071f0 (diff) | |
download | uml-history-9de5197b118e1c191434b59135fa89d66ed61479.tar.gz |
Fixed a bug caused by the copy_user longjmp jumping out of a signal handler,v_2_4_20_3
thus evading the restoration of the registers done there. This was exposed
by a Kylix executable.
-rw-r--r-- | arch/um/kernel/tt/include/uaccess.h | 31 | ||||
-rw-r--r-- | arch/um/kernel/tt/uaccess_user.c | 14 |
2 files changed, 32 insertions, 13 deletions
diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h index 42425a2..16b8052 100644 --- a/arch/um/kernel/tt/include/uaccess.h +++ b/arch/um/kernel/tt/include/uaccess.h @@ -46,18 +46,20 @@ extern int __do_copy_from_user(void *to, const void *from, int n, static inline int copy_from_user_tt(void *to, const void *from, int n) { - return(access_ok_tt(VERIFY_READ, from, n) ? - __do_copy_from_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); + if(!access_ok_tt(VERIFY_READ, from, n)) + return(n); + + return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); } static inline int copy_to_user_tt(void *to, const void *from, int n) { - return(access_ok_tt(VERIFY_WRITE, to, n) ? - __do_copy_to_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); + if(!access_ok_tt(VERIFY_WRITE, to, n)) + return(n); + + return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); } extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, @@ -67,7 +69,9 @@ static inline int strncpy_from_user_tt(char *dst, const char *src, int count) { int n; - if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT); + if(!access_ok_tt(VERIFY_READ, src, 1)) + return(-EFAULT); + n = __do_strncpy_from_user(dst, src, count, ¤t->thread.fault_addr, ¤t->thread.fault_catcher); @@ -87,10 +91,11 @@ static inline int __clear_user_tt(void *mem, int len) static inline int clear_user_tt(void *mem, int len) { - return(access_ok_tt(VERIFY_WRITE, mem, len) ? - __do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : len); + if(!access_ok_tt(VERIFY_WRITE, mem, len)) + return(len); + + return(__do_clear_user(mem, len, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); } extern int __do_strnlen_user(const char *str, unsigned long n, diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index 537ee9f..45a6bc8 100644 --- a/arch/um/kernel/tt/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c @@ -8,15 +8,20 @@ #include <string.h> #include "user_util.h" #include "uml_uaccess.h" +#include "task.h" +#include "kern_util.h" int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, __do_copy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(n - (fault - (unsigned long) from)); } @@ -29,11 +34,14 @@ static void __do_strncpy(void *dst, const void *src, int count) int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, __do_strncpy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(strlen(dst)); else return(-1); } @@ -46,11 +54,14 @@ static void __do_clear(void *to, const void *from, int n) int __do_clear_user(void *mem, unsigned long len, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, __do_clear, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(len - (fault - (unsigned long) mem)); } @@ -58,6 +69,7 @@ int __do_clear_user(void *mem, unsigned long len, int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; int ret; unsigned long *faddrp = (unsigned long *)fault_addr; jmp_buf jbuf; @@ -71,6 +83,8 @@ int __do_strnlen_user(const char *str, unsigned long n, } *fault_addr = NULL; *fault_catcher = NULL; + + TASK_REGS(get_current())->tt = save; return ret; } |