diff -Naur -X exclude-files ac_cur/arch/um/include/user_util.h ac/arch/um/include/user_util.h --- ac_cur/arch/um/include/user_util.h Fri Jun 1 20:50:47 2001 +++ ac/arch/um/include/user_util.h Fri Jun 1 21:06:05 2001 @@ -147,6 +147,7 @@ extern int load_initrd(char *filename, void *buf, int size); extern int ptrace_getregs(long pid, struct sys_pt_regs *regs_out); extern int ptrace_setregs(long pid, struct sys_pt_regs *regs_in); +extern void do_longjmp(void *p); #endif /* diff -Naur -X exclude-files ac_cur/arch/um/kernel/Makefile ac/arch/um/kernel/Makefile --- ac_cur/arch/um/kernel/Makefile Fri Jun 1 20:50:47 2001 +++ ac/arch/um/kernel/Makefile Fri Jun 1 21:06:32 2001 @@ -4,7 +4,7 @@ irq_user.o mem.o ptrace.o reboot.o resource.o \ setup.o signal_user.o smp.o syscall_kern.o \ syscall_user.o sys_call_table.o time.o time_kern.o tlb.o trap_kern.o \ - trap_user.o um_arch.o user_util.o + trap_user.o um_arch.o user_util.o uaccess_user.o OX_OBJS = ksyms.o process_kern.o signal_kern.o user_syms.o @@ -53,6 +53,9 @@ irq_user.o: irq_user.c $(CC) $(USER_CFLAGS) -c -o $@ $< +uaccess.o: uaccess_user.c + $(CC) $(USER_CFLAGS) -c -o $@ $< + unmap.o: unmap.c echo $(UNMAP_CFLAGS) $(CC) $(UNMAP_CFLAGS) -c -o $@ $< diff -Naur -X exclude-files ac_cur/arch/um/kernel/ksyms.c ac/arch/um/kernel/ksyms.c --- ac_cur/arch/um/kernel/ksyms.c Fri Jun 1 20:50:47 2001 +++ ac/arch/um/kernel/ksyms.c Fri Jun 1 21:10:04 2001 @@ -15,3 +15,4 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(__const_udelay); EXPORT_SYMBOL(sys_waitpid); +EXPORT_SYMBOL(__do_copy_from_user); diff -Naur -X exclude-files ac_cur/arch/um/kernel/process_kern.c ac/arch/um/kernel/process_kern.c --- ac_cur/arch/um/kernel/process_kern.c Fri Jun 1 20:50:47 2001 +++ ac/arch/um/kernel/process_kern.c Fri Jun 1 21:14:39 2001 @@ -666,9 +666,9 @@ return(kmalloc(size, GFP_KERNEL)); } -void *get_fault_addr(void) +unsigned long get_fault_addr(void) { - return(current->thread.fault_addr); + return((unsigned long) current->thread.fault_addr); } EXPORT_SYMBOL(get_fault_addr); diff -Naur -X exclude-files ac_cur/arch/um/kernel/sys_call_table.c ac/arch/um/kernel/sys_call_table.c --- ac_cur/arch/um/kernel/sys_call_table.c Fri Jun 1 20:50:47 2001 +++ ac/arch/um/kernel/sys_call_table.c Fri Jun 1 21:09:38 2001 @@ -137,7 +137,6 @@ extern syscall_handler_t sys_fchdir; extern syscall_handler_t sys_bdflush; extern syscall_handler_t sys_sysfs; -extern syscall_handler_t sys_personality; extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_setfsuid16; extern syscall_handler_t sys_setfsgid16; @@ -364,7 +363,7 @@ [ __NR_fchdir ] = sys_fchdir, [ __NR_bdflush ] = sys_bdflush, [ __NR_sysfs ] = sys_sysfs, - [ __NR_personality ] = sys_personality, + [ __NR_personality ] = (syscall_handler_t *) sys_personality, [ __NR_afs_syscall ] = sys_ni_syscall, [ __NR_setfsuid ] = sys_setfsuid16, [ __NR_setfsgid ] = sys_setfsgid16, diff -Naur -X exclude-files ac_cur/arch/um/kernel/trap_kern.c ac/arch/um/kernel/trap_kern.c --- ac_cur/arch/um/kernel/trap_kern.c Fri Jun 1 20:50:47 2001 +++ ac/arch/um/kernel/trap_kern.c Fri Jun 1 21:18:02 2001 @@ -43,12 +43,13 @@ else if(expand_stack(vma, address)) ok = 0; } if(!ok){ - if(current->thread.fault_addr != NULL){ - unsigned long new_ip = - (unsigned long) current->thread.fault_addr; + if (current->thread.fault_catcher != NULL) { current->thread.fault_addr = (void *) address; up_read(&mm->mmap_sem); - return(new_ip); + do_longjmp(current->thread.fault_catcher); + } + else if(current->thread.fault_addr != NULL){ + panic("fault_addr set but no fault catcher"); } if(!is_user) panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", diff -Naur -X exclude-files ac_cur/arch/um/kernel/trap_user.c ac/arch/um/kernel/trap_user.c --- ac_cur/arch/um/kernel/trap_user.c Fri Jun 1 20:50:47 2001 +++ ac/arch/um/kernel/trap_user.c Fri Jun 1 21:08:37 2001 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -277,7 +278,6 @@ void segv_handler(int sig, void *sc, int usermode) { struct sigcontext_struct *context = sc; - unsigned long new_ip; int index; lock_trap(); @@ -290,9 +290,8 @@ segfault_record[index].is_write = SC_FAULT_WRITE(context); segfault_record[index].sp = SC_SP(context); segfault_record[index].is_user = usermode; - new_ip = segv(SC_FAULT_ADDR(context), SC_IP(context), - SC_FAULT_WRITE(context), usermode); - if(new_ip != 0) SC_IP(context) = new_ip; + segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context), + usermode); } static void (*handlers[])(int, void *, int) = { @@ -335,6 +334,13 @@ errno = save_errno; } +void do_longjmp(void *p) +{ + jmp_buf *jbuf = (jmp_buf *)p; + + longjmp(*jbuf, 1); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff -Naur -X exclude-files ac_cur/arch/um/kernel/uaccess_user.c ac/arch/um/kernel/uaccess_user.c --- ac_cur/arch/um/kernel/uaccess_user.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/kernel/uaccess_user.c Fri Jun 1 21:04:44 2001 @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) + * Licensed under the GPL + */ + +#include +#include +#include "user_util.h" + +static unsigned long __do_user_copy(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher, + void (*op)(void *to, const void *from, + int n)) +{ + unsigned long *faddrp = (unsigned long *) fault_addr, ret; + + jmp_buf jbuf; + *fault_catcher = &jbuf; + if (setjmp(jbuf) == 0) { + (*op)(to, from, n); + ret = 0; + } else { + ret = *faddrp; + } + *fault_addr = NULL; + *fault_catcher = NULL; + return ret; +} + +static void __do_copy(void *to, const void *from, int n) +{ + memcpy(to, from, n); +} + +int __do_copy_from_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + + fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, + __do_copy); + if(fault == 0) return(0); + else return(n - (fault - (unsigned long) from)); +} + + +int __do_copy_to_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + + fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, + __do_copy); + if(fault == 0) return(0); + else return(n - (fault - (unsigned long) to)); +} + +static void __do_strncpy(void *dst, const void *src, int count) +{ + strncpy(dst, src, count); +} + +int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + + fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, + __do_strncpy); + if(fault == 0) return(strlen(dst)); + else return(-1); +} + +static void __do_clear(void *to, const void *from, int n) +{ + memset(to, 0, n); +} + +int __do_clear_user(void *mem, unsigned long len, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + + fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, + __do_clear); + if(fault == 0) return(0); + else return(len - (fault - (unsigned long) mem)); +} + +int __do_strnlen_user(const char *str, unsigned long n, + void **fault_addr, void **fault_catcher) +{ + int ret; + unsigned long *faddrp = (unsigned long *)fault_addr; + jmp_buf jbuf; + *fault_catcher = &jbuf; + if (setjmp(jbuf) == 0) { + ret = strlen(str) + 1; + } else { + ret = *faddrp - (unsigned long)str; + } + *fault_addr = NULL; + *fault_catcher = NULL; + return ret; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_cur/include/asm-um/processor.h ac/include/asm-um/processor.h --- ac_cur/include/asm-um/processor.h Fri Jun 1 21:05:28 2001 +++ ac/include/asm-um/processor.h Fri Jun 1 21:08:50 2001 @@ -41,6 +41,7 @@ int repeat_syscall; int mm_changes; void *fault_addr; + void *fault_catcher; void *brk; int sigreturn_syscall; struct { diff -Naur -X exclude-files ac_cur/include/asm-um/uaccess.h ac/include/asm-um/uaccess.h --- ac_cur/include/asm-um/uaccess.h Fri Jun 1 20:57:57 2001 +++ ac/include/asm-um/uaccess.h Fri Jun 1 21:10:29 2001 @@ -7,8 +7,10 @@ #define __UM_UACCESS_H #include "linux/string.h" +#include "linux/sched.h" #include "asm/processor.h" #include "asm/errno.h" +#include "asm/current.h" #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -50,64 +52,45 @@ #define segment_eq(a, b) (1) -extern void *get_fault_addr(void); -extern void set_fault_addr(void *addr); +extern unsigned long get_fault_addr(void); -static inline int __copy_from_user(void *to, const void *from, int n) -{ - int ret = 0; - - set_fault_addr(&&error); - memcpy(to, from, n); - goto out; - error: - ret = n - ((unsigned long) get_fault_addr() - (unsigned long) from); - out: - set_fault_addr(NULL); - return(ret); -} +extern int __do_copy_from_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher); static inline int copy_from_user(void *to, const void *from, int n) { return(access_ok(VERIFY_READ, from, n) ? - __copy_from_user(to, from, n) : \ - n); + __do_copy_from_user(to, from, n, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : n); } -static inline int __copy_to_user(void *to, const void *from, int n) -{ - int ret = 0; +#define __copy_from_user(to, from, n) copy_from_user(to, from, n) - set_fault_addr(&&error); - memcpy(to, from, n); - goto out; - error: - ret = n - ((unsigned long) get_fault_addr() - (unsigned long) to); - out: - set_fault_addr(NULL); - return(ret); -} +extern int __do_copy_to_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher); static inline int copy_to_user(void *to, const void *from, int n) { return(access_ok(VERIFY_WRITE, to, n) ? - __copy_from_user(to, from, n) : \ - n); + __do_copy_from_user(to, from, n, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : n); } +#define __copy_to_user(to, from, n) copy_to_user(to, from, n) + #define __get_user(x, ptr) \ ({ \ - __label__ out; \ __typeof__(ptr) __private_ptr = ptr; \ __typeof__(*(__private_ptr)) __private_val; \ int __private_ret = -EFAULT; \ (x) = 0; \ - current->thread.fault_addr = &&out; \ - memcpy(&__private_val, (__private_ptr), sizeof(*(__private_ptr))); \ - (x) = (__typeof__(*(__private_ptr))) __private_val; \ - __private_ret = 0; \ - out: \ - current->thread.fault_addr = NULL; \ + if (__copy_from_user(&__private_val, (__private_ptr), \ + sizeof(*(__private_ptr))) == 0) {\ + (x) = (__typeof__(*(__private_ptr))) __private_val; \ + __private_ret = 0; \ + } \ __private_ret; \ }) @@ -120,16 +103,14 @@ #define __put_user(x, ptr) \ ({ \ - __label__ out; \ __typeof__(ptr) __private_ptr = ptr; \ __typeof__(*(__private_ptr)) __private_val; \ int __private_ret = -EFAULT; \ - current->thread.fault_addr = &&out; \ __private_val = (__typeof__(*(__private_ptr))) (x); \ - memcpy((__private_ptr), &__private_val, sizeof(*(__private_ptr))); \ - __private_ret = 0; \ - out: \ - current->thread.fault_addr = NULL; \ + if (__copy_to_user((__private_ptr), &__private_val, \ + sizeof(*(__private_ptr))) == 0) { \ + __private_ret = 0; \ + } \ __private_ret; \ }) @@ -140,53 +121,41 @@ __put_user(x, private_ptr) : -EFAULT); \ }) -#define __strncpy_from_user(dst, src, count) \ -({ __label__ out; \ - int __private_ret = -EFAULT; \ - current->thread.fault_addr = &&out; \ - strncpy(dst, src, count); \ - __private_ret = strlen(dst); \ - out: \ - current->thread.fault_addr = NULL; \ - __private_ret; \ -}) +extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, + void **fault_addr, void **fault_catcher); -#define strncpy_from_user(dst, src, count) \ - (access_ok(VERIFY_READ, src, 1) ? \ - __strncpy_from_user(dst, src, count) : \ - -EFAULT) - -#define __clear_user(mem, len) \ -({ __label__ error, out; \ - int __private_ret = 0; \ - current->thread.fault_addr = &&error; \ - memset((mem), 0, (len)); \ - goto out; \ - error: \ - __private_ret = (len) - ((unsigned long) current->thread.fault_addr - \ - (unsigned long) (mem)); \ - out: \ - current->thread.fault_addr = NULL; \ - __private_ret; \ -}) +static inline int strncpy_from_user(char *dst, const char *src, int count) +{ + int n; -#define clear_user(mem, len) \ - (access_ok(VERIFY_WRITE, mem, len) ? __clear_user(mem, len) : len) + if(!access_ok(VERIFY_READ, src, 1)) return(-EFAULT); + n = __do_strncpy_from_user(dst, src, count, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher); + if(n < 0) return(-EFAULT); + return(n); +} -#define strnlen_user(str, n) \ -({ __label__ out, error; \ - int __private_ret = 0; \ - current->thread.fault_addr = &&error; \ - __private_ret = strlen(str) + 1; \ - goto out; \ - error: \ - __private_ret = (unsigned long) current->thread.fault_addr - \ - (unsigned long) str; \ - out: \ - current->thread.fault_addr = NULL; \ - __private_ret; \ -}) +extern int __do_clear_user(void *mem, size_t len, void **fault_addr, + void **fault_catcher); + +static inline int clear_user(void *mem, int len) +{ + return(access_ok(VERIFY_WRITE, mem, len) ? + __do_clear_user(mem, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : len); +} + +extern int __do_strnlen_user(const char *str, unsigned long n, + void **fault_addr, void **fault_catcher); +static inline int strnlen_user(void *str, int len) +{ + return(__do_strnlen_user(str, len, + ¤t_task->thread.fault_addr, + ¤t_task->thread.fault_catcher)); +} #define strlen_user(str) strnlen_user(str, ~0UL >> 1)