consolidate compat readv/writev/execve/select/nfsservctl [v2]
Subsystems (4)
I'm following up with patches to introduce new compat_sys_* functions for the largest four ones. All of these had some bugs on most architectures, usually resulting from missing updates after the native handler was changed.
This is the second version of these cleanups that include a fix for compat_sys_select and an update from Arun Sharma to use compat_do_execve on ia64 as well.
For readv, writev, execve and select, ia64 and x86_64 use a different method from the others and I chose to use the more common one, which is a bit more code but avoids an extra copy of the user data.
The patches are also available at
http://www.arndb.de/patches/linux/2.6.6-rc1/ and apply cleanly to 2.6.6-rc1 and 2.6.5-mm6. They are tested on x86_64, ia64 and s390.
Please consider for 2.6.6-rc*-mm* and 2.6.7.
Arnd <><
PATCH 1/4 Consolidate sys32_readv and sys32_writev
The seven implementations of this have gone out of sync and are mostly buggy. The new compat_sys_* version is based on the ppc64 implementation, which most closely resembles the code in sys_readv/sys_writev.
Tested on x86_64, ia64 and s390.
arch/ia64/ia32/ia32_entry.S | 4 arch/ia64/ia32/sys_ia32.c | 79 --------------- arch/mips/kernel/linux32.c | 144 ---------------------------- arch/mips/kernel/scall64-n32.S | 4 arch/mips/kernel/scall64-o32.S | 4 arch/parisc/kernel/sys_parisc32.c | 143 ---------------------------- arch/parisc/kernel/syscall_table.S | 4 arch/ppc64/kernel/misc.S | 4 arch/ppc64/kernel/sys_ppc32.c | 172 ---------------------------------- arch/s390/kernel/compat_linux.c | 138 --------------------------- arch/s390/kernel/compat_wrapper.S | 16 +-- arch/s390/kernel/syscalls.S | 4 arch/sparc64/kernel/sys_sparc32.c | 176 ----------------------------------- arch/sparc64/kernel/sys_sunos32.c | 7 - arch/sparc64/kernel/systbls.S | 2 arch/x86_64/ia32/ia32entry.S | 4 arch/x86_64/ia32/sys_ia32.c | 98 ------------------- fs/compat.c | 186 +++++++++++++++++++++++++++++++++++++ include/linux/compat.h | 6 + 19 files changed, 217 insertions(+), 978 deletions(-)
===== arch/ia64/ia32/ia32_entry.S 1.35 vs edited =====
arch/ia64/ia32/ia32_entry.S +2 -2
@@ -353,8 +353,8 @@ data8 sys32_select data8 sys_flock data8 sys32_msync - data8 sys32_readv /* 145 */ - data8 sys32_writev + data8 compat_sys_readv /* 145 */ + data8 compat_sys_writev data8 sys_getsid data8 sys_fdatasync data8 sys32_sysctl
===== arch/ia64/ia32/sys_ia32.c 1.94 vs edited =====
arch/ia64/ia32/sys_ia32.c +0 -79
85 lines not on this page · raw message
===== arch/mips/kernel/linux32.c 1.22 vs edited =====
arch/mips/kernel/linux32.c +0 -144
150 lines not on this page · raw message
===== arch/mips/kernel/scall64-n32.S 1.2 vs edited =====
arch/mips/kernel/scall64-n32.S +2 -2
@@ -128,8 +128,8 @@ PTR compat_sys_ioctl /* 6015 */ PTR sys_pread64 PTR sys_pwrite64 - PTR sys32_readv - PTR sys32_writev + PTR compat_sys_readv + PTR compat_sys_writev PTR sys_access /* 6020 */ PTR sys_pipe PTR sys32_select
===== arch/mips/kernel/scall64-o32.S 1.2 vs edited =====
arch/mips/kernel/scall64-o32.S +2 -2
@@ -400,8 +400,8 @@ sys sys32_select 5 sys sys_flock 2 sys sys_msync 3 - sys sys32_readv 3 /* 4145 */ - sys sys32_writev 3 + sys compat_sys_readv 3 /* 4145 */ + sys compat_sys_writev 3 sys sys_cacheflush 3 sys sys_cachectl 3 sys sys_sysmips 4
===== arch/parisc/kernel/sys_parisc32.c 1.25 vs edited =====
arch/parisc/kernel/sys_parisc32.c +0 -143
149 lines not on this page · raw message
===== arch/parisc/kernel/syscall_table.S 1.4 vs edited =====
arch/parisc/kernel/syscall_table.S +2 -2
@@ -236,8 +236,8 @@ ENTRY_SAME(flock) ENTRY_SAME(msync) /* struct iovec contains pointers */ - ENTRY_DIFF(readv) /* 145 */ - ENTRY_DIFF(writev) + ENTRY_COMP(readv) /* 145 */ + ENTRY_COMP(writev) ENTRY_SAME(getsid) ENTRY_SAME(fdatasync) /* struct __sysctl_args is a mess */
===== arch/ppc64/kernel/misc.S 1.75 vs edited =====
arch/ppc64/kernel/misc.S +2 -2
@@ -717,8 +717,8 @@ .llong .ppc32_select .llong .sys_flock .llong .sys_msync - .llong .sys32_readv /* 145 */ - .llong .sys32_writev + .llong .compat_sys_readv /* 145 */ + .llong .compat_sys_writev .llong .sys32_getsid .llong .sys_fdatasync .llong .sys32_sysctl
===== arch/ppc64/kernel/sys_ppc32.c 1.86 vs edited =====
arch/ppc64/kernel/sys_ppc32.c +0 -172
178 lines not on this page · raw message
===== arch/s390/kernel/compat_linux.c 1.19 vs edited =====
arch/s390/kernel/compat_linux.c +0 -138
144 lines not on this page · raw message
===== arch/s390/kernel/compat_wrapper.S 1.9 vs edited =====
arch/s390/kernel/compat_wrapper.S +8 -8
@@ -663,19 +663,19 @@ lgfr %r4,%r4 # int jg sys_msync # branch to system call - .globl sys32_readv_wrapper -sys32_readv_wrapper: + .globl compat_sys_readv_wrapper +compat_sys_readv_wrapper: lgfr %r2,%r2 # int - llgtr %r3,%r3 # const struct iovec_emu31 * + llgtr %r3,%r3 # const struct compat_iovec * llgfr %r4,%r4 # unsigned long - jg sys32_readv # branch to system call + jg compat_sys_readv # branch to system call - .globl sys32_writev_wrapper -sys32_writev_wrapper: + .globl compat_sys_writev_wrapper +compat_sys_writev_wrapper: lgfr %r2,%r2 # int - llgtr %r3,%r3 # const struct iovec_emu31 * + llgtr %r3,%r3 # const struct compat_iovec * llgfr %r4,%r4 # unsigned long - jg sys32_writev # branch to system call + jg compat_sys_writev # branch to system call .globl sys32_getsid_wrapper sys32_getsid_wrapper:
===== arch/s390/kernel/syscalls.S 1.9 vs edited =====
arch/s390/kernel/syscalls.S +2 -2
@@ -153,8 +153,8 @@ SYSCALL(sys_select,sys_select,sys32_select_wrapper) SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper) SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper) -SYSCALL(sys_readv,sys_readv,sys32_readv_wrapper) /* 145 */ -SYSCALL(sys_writev,sys_writev,sys32_writev_wrapper) +SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper) /* 145 */ +SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper) SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper) SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper) SYSCALL(sys_sysctl,sys_sysctl,sys32_sysctl_wrapper)
===== arch/sparc64/kernel/sys_sparc32.c 1.95 vs edited =====
arch/sparc64/kernel/sys_sparc32.c +0 -176
182 lines not on this page · raw message
===== arch/sparc64/kernel/sys_sunos32.c 1.39 vs edited =====
arch/sparc64/kernel/sys_sunos32.c +2 -5
@@ -1203,9 +1203,6 @@return ret; } -extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count); -extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count); - asmlinkage int sunos_read(unsigned int fd, u32 buf, u32 count) {int ret;
@@ -1218,7 +1215,7 @@ {int ret; - ret =check_nonblock (sys32_readv (fd, vector, count), fd); + ret =check_nonblock (compat_sys_readv (fd, (void *)A (vector), count), fd);return ret; }
@@ -1234,7 +1231,7 @@ {int ret; - ret =check_nonblock (sys32_writev (fd, vector, count), fd); + ret =check_nonblock (compat_sys_writev (fd, (void *)A (vector), count), fd);return ret; }
===== arch/sparc64/kernel/systbls.S 1.52 vs edited =====
arch/sparc64/kernel/systbls.S +1 -1
@@ -43,7 +43,7 @@ .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid /*110*/ .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall .word sys_getgroups, sys32_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd -/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod +/*120*/ .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod .word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate /*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64
===== arch/x86_64/ia32/ia32entry.S 1.31 vs edited =====
arch/x86_64/ia32/ia32entry.S +2 -2
@@ -450,8 +450,8 @@ .quad sys32_select .quad sys_flock .quad sys_msync - .quad sys32_readv /* 145 */ - .quad sys32_writev + .quad compat_sys_readv /* 145 */ + .quad compat_sys_writev .quad sys_getsid .quad sys_fdatasync .quad sys32_sysctl /* sysctl */
===== arch/x86_64/ia32/sys_ia32.c 1.57 vs edited =====
arch/x86_64/ia32/sys_ia32.c +0 -98
104 lines not on this page · raw message
===== fs/compat.c 1.22 vs edited =====
fs/compat.c +186 -0
198 lines not on this page · raw message
===== include/linux/compat.h 1.20 vs edited =====
include/linux/compat.h +6 -0
@@ -117,5 +117,11 @@long compat_sys_shmctl (int first,int second,void __user *uptr);long compat_sys_semtimedop (int semid,struct sembuf __user *tsems,unsigned nsems,const struct compat_timespec __user *timeout); + +asmlinkage ssize_t compat_sys_readv(unsigned long fd, +const struct compat_iovec __user *vec,unsigned long vlen); +asmlinkage ssize_t compat_sys_writev(unsigned long fd, +const struct compat_iovec __user *vec,unsigned long vlen); +#endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */
PATCH 2/4 Consolidate do_execve32
In reply to Arnd BergmannThe code for sys32_execve/do_execve32 in most of the seven versions was copied from fs/exec.c but not kept up-to-date. The new compat_do_execve() function is based on the mips code and has been resync'ed with do_execve(). IA64 changes are from Arun Sharma.
Tested on x86_64, ia64 and s390
arch/ia64/ia32/sys_ia32.c | 70 ++--------- arch/mips/kernel/linux32.c | 228 ------------------------------------- arch/parisc/kernel/sys_parisc32.c | 187 ------------------------------ arch/ppc64/kernel/sys_ppc32.c | 187 ------------------------------ arch/s390/kernel/compat_linux.c | 187 ------------------------------ arch/sparc64/kernel/sys_sparc32.c | 195 -------------------------------- arch/x86_64/ia32/sys_ia32.c | 101 ++-------------- fs/compat.c | 231 ++++++++++++++++++++++++++++++++++++++ include/linux/compat.h | 3 9 files changed, 275 insertions(+), 1114 deletions(-)
===== arch/ia64/ia32/sys_ia32.c 1.95 vs edited =====
arch/ia64/ia32/sys_ia32.c +14 -56
@@ -90,58 +90,17 @@/* XXX make per-mm: */ static DECLARE_MUTEX (ia32_mmap_sem); -static int -nargs (unsigned int arg,char **ap) -{ -unsigned int addr; -int n, err; - -if (!arg) -return 0 ; - - n =0 ; -do { - err =get_user (addr, (unsigned int *)A (arg)); -if (err) -return err; -if (ap) - *ap++ = (char *)A (addr); - arg +=sizeof (unsigned int ); - n++; - }while (addr); -return n -1 ; -} -asmlinkage long -sys32_execve (char *filename,unsigned int argv,unsigned int envp, -struct pt_regs *regs) +sys32_execve (char *name,compat_uptr_t __user *argv,compat_uptr_t __user *envp,struct pt_regs *regs) { +long error; +char *filename;unsigned long old_map_base, old_task_size, tssd; -char **av, **ae; -int na, ne, len; -long r; - - na =nargs (argv,NULL ); -if (na <0 ) -return na; - ne =nargs (envp,NULL ); -if (ne <0 ) -return ne; - len = (na + ne +2 ) *sizeof (*av); - av =kmalloc (len,GFP_KERNEL ); -if (!av) -return -ENOMEM ; - - ae = av + na +1 ; - av[na] =NULL ; - ae[ne] =NULL ; - - r =nargs (argv, av); -if (r <0 ) - goto out; - r =nargs (envp, ae); -if (r <0 ) - goto out; + + filename =getname (name); + error =PTR_ERR (filename); +if (IS_ERR (filename)) +return error; old_map_base = current->thread.map_base; old_task_size = current->thread.task_size;
@@ -153,19 +112,18 @@ia64_set_kr (IA64_KR_IO_BASE , current->thread.old_iob);ia64_set_kr (IA64_KR_TSSD , current->thread.old_k1); -set_fs (KERNEL_DS ); - r =sys_execve (filename, av, ae, regs); -if (r <0 ) { + error =compat_do_execve (filename, argv, envp, regs); +putname (filename); + +if (error <0 ) {/* oops, execve failed, switch back to old values... */ ia64_set_kr (IA64_KR_IO_BASE ,IA32_IOBASE );ia64_set_kr (IA64_KR_TSSD , tssd); current->thread.map_base = old_map_base; current->thread.task_size = old_task_size; -set_fs (USER_DS );/* establish new task-size as the address-limit */ } - out: -kfree (av); -return r; + +return error; }int cp_compat_stat (struct kstat *stat,struct compat_stat *ubuf)
===== arch/mips/kernel/linux32.c 1.23 vs edited =====
arch/mips/kernel/linux32.c +3 -225
243 lines not on this page · raw message
===== arch/parisc/kernel/sys_parisc32.c 1.26 vs edited =====
arch/parisc/kernel/sys_parisc32.c +2 -185
199 lines not on this page · raw message
===== arch/ppc64/kernel/sys_ppc32.c 1.87 vs edited =====
arch/ppc64/kernel/sys_ppc32.c +1 -186
199 lines not on this page · raw message
===== arch/s390/kernel/compat_linux.c 1.20 vs edited =====
arch/s390/kernel/compat_linux.c +3 -184
202 lines not on this page · raw message
===== arch/sparc64/kernel/sys_sparc32.c 1.96 vs edited =====
arch/sparc64/kernel/sys_sparc32.c +3 -192
213 lines not on this page · raw message
===== arch/x86_64/ia32/sys_ia32.c 1.58 vs edited =====
arch/x86_64/ia32/sys_ia32.c +15 -86
108 lines not on this page · raw message
===== fs/compat.c 1.23 vs edited =====
fs/compat.c +231 -0
234 lines not on this page · raw message
===== include/linux/compat.h 1.21 vs edited =====
include/linux/compat.h +3 -0
@@ -123,5 +123,8 @@ asmlinkage ssize_t compat_sys_writev(unsigned long fd,const struct compat_iovec __user *vec,unsigned long vlen); +int compat_do_execve (char * filename,compat_uptr_t __user *argv, +compat_uptr_t __user *envp,struct pt_regs * regs); +#endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */
PATCH 3/4 Consolidate sys32_select
In reply to Arnd Bergmannsys32_select has seven mostly but not exactly identical versions, so consolidate them as compat_sys_select. Based on the ppc64 implementation, which most closely resembles sys_select. One bug that was not caught by LTP has been fixed since the first version of this patch.
tested x86_64, ia64 and s390.
arch/ia64/ia32/ia32_entry.S | 2 arch/ia64/ia32/sys_ia32.c | 108 --------------------- arch/mips/kernel/linux32.c | 161 ------------------------------- arch/mips/kernel/scall64-n32.S | 2 arch/mips/kernel/scall64-o32.S | 2 arch/parisc/kernel/sys_parisc32.c | 121 ----------------------- arch/parisc/kernel/syscall_table.S | 2 arch/ppc64/kernel/sys_ppc32.c | 163 -------------------------------- arch/s390/kernel/compat_linux.c | 154 ------------------------------ arch/s390/kernel/compat_wrapper.S | 14 +- arch/s390/kernel/syscalls.S | 2 arch/sparc64/kernel/sys_sparc32.c | 152 ----------------------------- arch/sparc64/kernel/sys_sunos32.c | 9 - arch/sparc64/kernel/systbls.S | 4 arch/x86_64/ia32/ia32entry.S | 2 arch/x86_64/ia32/sys_ia32.c | 105 -------------------- fs/compat.c | 188 +++++++++++++++++++++++++++++++++++++ include/linux/compat.h | 4 18 files changed, 218 insertions(+), 977 deletions(-)
===== arch/ia64/ia32/ia32_entry.S 1.36 vs edited =====
arch/ia64/ia32/ia32_entry.S +1 -1
@@ -350,7 +350,7 @@ data8 sys_setfsgid /* 16-bit version */ data8 sys_llseek /* 140 */ data8 sys32_getdents - data8 sys32_select + data8 compat_sys_select data8 sys_flock data8 sys32_msync data8 compat_sys_readv /* 145 */
===== arch/ia64/ia32/sys_ia32.c 1.95 vs edited =====
arch/ia64/ia32/sys_ia32.c +2 -106
120 lines not on this page · raw message
===== arch/mips/kernel/linux32.c 1.23 vs edited =====
arch/mips/kernel/linux32.c +0 -161
167 lines not on this page · raw message
===== arch/mips/kernel/scall64-n32.S 1.3 vs edited =====
arch/mips/kernel/scall64-n32.S +1 -1
@@ -132,7 +132,7 @@ PTR compat_sys_writev PTR sys_access /* 6020 */ PTR sys_pipe - PTR sys32_select + PTR compat_sys_select PTR sys_sched_yield PTR sys_mremap PTR sys_msync /* 6025 */
===== arch/mips/kernel/scall64-o32.S 1.3 vs edited =====
arch/mips/kernel/scall64-o32.S +1 -1
@@ -397,7 +397,7 @@ sys sys_setfsgid 1 sys sys32_llseek 5 /* 4140 */ sys sys32_getdents 3 - sys sys32_select 5 + sys compat_sys_select 5 sys sys_flock 2 sys sys_msync 3 sys compat_sys_readv 3 /* 4145 */
===== arch/parisc/kernel/sys_parisc32.c 1.26 vs edited =====
arch/parisc/kernel/sys_parisc32.c +0 -121
133 lines not on this page · raw message
===== arch/parisc/kernel/syscall_table.S 1.5 vs edited =====
arch/parisc/kernel/syscall_table.S +1 -1
@@ -232,7 +232,7 @@ ENTRY_DIFF(getdents) /* it is POSSIBLE that select will be OK because even though fd_set * contains longs, the macros and sizes are clever. */ - ENTRY_DIFF(select) + ENTRY_COMP(select) ENTRY_SAME(flock) ENTRY_SAME(msync) /* struct iovec contains pointers */
===== arch/ppc64/kernel/sys_ppc32.c 1.87 vs edited =====
arch/ppc64/kernel/sys_ppc32.c +4 -159
171 lines not on this page · raw message
===== arch/s390/kernel/compat_linux.c 1.20 vs edited =====
arch/s390/kernel/compat_linux.c +0 -154
160 lines not on this page · raw message
===== arch/s390/kernel/compat_wrapper.S 1.10 vs edited =====
arch/s390/kernel/compat_wrapper.S +7 -7
@@ -641,14 +641,14 @@ llgfr %r4,%r4 # unsigned int jg sys32_getdents # branch to system call - .globl sys32_select_wrapper -sys32_select_wrapper: + .globl compat_sys_select_wrapper +compat_sys_select_wrapper: lgfr %r2,%r2 # int - llgtr %r3,%r3 # fd_set * - llgtr %r4,%r4 # fd_set * - llgtr %r5,%r5 # fd_set * - llgtr %r6,%r6 # struct timeval_emu31 * - jg sys32_select # branch to system call + llgtr %r3,%r3 # compat_fd_set * + llgtr %r4,%r4 # compat_fd_set * + llgtr %r5,%r5 # compat_fd_set * + llgtr %r6,%r6 # struct compat_timeval * + jg compat_sys_select # branch to system call .globl sys32_flock_wrapper sys32_flock_wrapper:
===== arch/s390/kernel/syscalls.S 1.10 vs edited =====
arch/s390/kernel/syscalls.S +1 -1
@@ -150,7 +150,7 @@ SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */ SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper) /* 140 */ SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper) -SYSCALL(sys_select,sys_select,sys32_select_wrapper) +SYSCALL(sys_select,sys_select,compat_sys_select_wrapper) SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper) SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper) SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper) /* 145 */
===== arch/sparc64/kernel/sys_sparc32.c 1.96 vs edited =====
arch/sparc64/kernel/sys_sparc32.c +0 -152
158 lines not on this page · raw message
===== arch/sparc64/kernel/sys_sunos32.c 1.40 vs edited =====
arch/sparc64/kernel/sys_sunos32.c +3 -6
@@ -528,18 +528,15 @@return ret; } -/* SunOS mount system call emulation */ -extern asmlinkage int -sys32_select (int n,u32 inp,u32 outp,u32 exp,u32 tvp); - asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x) {int ret;/* SunOS binaries expect that select won't change the tvp contents */ - ret =sys32_select (width, inp, outp, exp, tvp_x); + ret =compat_sys_select (width,compat_ptr (inp),compat_ptr (outp), +compat_ptr (exp),compat_ptr (tvp_x));if (ret == -EINTR && tvp_x) { -struct compat_timeval *tvp = (struct compat_timeval *)A (tvp_x); +struct compat_timeval *tvp =compat_ptr (tvp_x);time_t sec, usec;__get_user (sec, &tvp->tv_sec);
===== arch/sparc64/kernel/systbls.S 1.53 vs edited =====
arch/sparc64/kernel/systbls.S +2 -2
@@ -37,7 +37,7 @@ .word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys32_getgroups16 /*80*/ .word sys32_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64 .word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid -/*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid +/*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, compat_sys_select, sys_setfsgid .word sys_fsync, sys_setpriority32, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid
@@ -65,7 +65,7 @@ .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex /*220*/ .word compat_sys_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 -/*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, compat_statfs64 +/*230*/ .word compat_sys_select, sys_time, sys_nis_syscall, sys_stime, compat_statfs64 .word compat_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
===== arch/x86_64/ia32/ia32entry.S 1.32 vs edited =====
arch/x86_64/ia32/ia32entry.S +1 -1
@@ -447,7 +447,7 @@ .quad sys_setfsgid16 .quad sys_llseek /* 140 */ .quad sys32_getdents - .quad sys32_select + .quad compat_sys_select .quad sys_flock .quad sys_msync .quad compat_sys_readv /* 145 */
===== arch/x86_64/ia32/sys_ia32.c 1.58 vs edited =====
arch/x86_64/ia32/sys_ia32.c +2 -103
117 lines not on this page · raw message
===== fs/compat.c 1.23 vs edited =====
fs/compat.c +188 -0
191 lines not on this page · raw message
===== include/linux/compat.h 1.21 vs edited =====
include/linux/compat.h +4 -0
@@ -126,5 +126,9 @@int compat_do_execve (char * filename,compat_uptr_t __user *argv,compat_uptr_t __user *envp,struct pt_regs * regs); +asmlinkage long compat_sys_select (int n,compat_ulong_t __user *inp, +compat_ulong_t __user *outp,compat_ulong_t __user *exp, +struct compat_timeval __user *tvp); +#endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */
Quoted 1 line
Re: [PATCH 3/4] Consolidate sys32_select
On Fri, 2004-04-16 at 18:05, Arnd Bergmann wrote:
Hi Arnd.
Quoted 7 lines
sys32_selecthas seven mostly but not exactly identical versions, so consolidate them ascompat_sys_select. Based on the ppc64 implementation, which most closely resemblessys_select. One bug that was not caught by LTP has been fixed since the first version of this patch.tested
x86_64, ia64 and s390.
This breaks sparc64. rsync -> select() -> compat_sys_select() with a user pointer that has bit (1<<32) set.
I came to this conclusion after having added lots of debug printk's. Here's the debug printk:
compat_sys_select: before verify_area 00000001efff6468
The address printed is the address of the tvp argument.
The only weird thing with it is the (1<<32) bit, otherwise it looks like the other pointers (this doesn't happen for all select()'s but I have a testcase with rsync that reproduces it every time in exactly the same way)
When this happens __get_user() generates a pagefault and we somehow get stuck in a pagefault loop, we livelock.
(verify_area() is a noop on sparc64)
How it used to look in arch/sparc64/kernel/sys_sparc32.c
Quoted 4 lines
arch/sparc64/kernel/sys_sparc32.c +0
-4-asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x) -{ -fd_set_bits fds; -struct compat_timeval *tvp = (struct compat_timeval *)AA (tvp_x);
[snip]
arch/mips/kernel/linux32.c line 607
Quoted 4 lines
arch/mips/kernel/linux32.c +0
-4-if ((ret =verify_area (VERIFY_READ , tvp,sizeof (*tvp))) - || (ret =__get_user (sec, &tvp->tv_sec)) - || (ret =__get_user (usec, &tvp->tv_usec))) - goto out_nofds;
What it looks like now:
asmlinkage long
compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
{
[snip]
time_t sec, usec; if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp))) || (ret = __get_user(sec, &tvp->tv_sec)) || (ret = __get_user(usec, &tvp->tv_usec))) goto out_nofds;
This combined with this comment from arch/sparc64/kernel/sys_sparc32.c
/* Things to consider: the low-level assembly stub does
srl x, 0, x for first four arguments, so if you have pointer to something in the first four arguments, just declare it as a pointer, not u32. On the other side, arguments from 5th onwards should be declared as u32 for pointers, and need AA() around each usage.
I added some simple casting to get rid of the high-bit and now rsync works just fine and we don't livelock.
Do you have any ideas how to cleanly get this working again? Masking argument five and onwards with 0xffffffffUL ?
On a related note, a quick look through fs/compat.c indicates that we have the same problem with these compat functions as well:
compat_sys_io_geteventcompat_sys_mount
Signature · 1 line
/Martin
Re: [PATCH 3/4] Consolidate sys32_select
Just fix the code to use compat_ptr(). That's what we created that macro for :-)
Re: [PATCH 3/4] Consolidate sys32_select
Quoted 2 lines · David S. Miller
Just fix the code to use
compat_ptr(). That's what we created that macro for :-)
You mean in compat_sys_select() ?compat_ptr() takes an u32 as argument, needs casting, ugly. But you want it done that way?
I see this problem when compat_sys_select() is called directly from syscall, not via sunos_select() which uses compat_ptr()
Signature · 1 line
/Martin
PATCH 4/4 Consolidate sys32_nfsservctl
In reply to Arnd Bergmannsys32_nfsservctl is the largest remaining syscall emulation handler that can be consolidated. mips and ia64 currently don't use this at all, parisc has a simpler implementation than the one used by s390, sparc ppc and that the new compat_sys_nfsservctl is based on.
The user access checks in the code are inconsistant at least, which should be fixed here.
Compile tested only due to lack of proper test setup.
arch/ia64/ia32/sys_ia32.c | 170 -------------------------- arch/parisc/kernel/sys_parisc32.c | 88 ------------- arch/parisc/kernel/syscall_table.S | 2 arch/ppc64/kernel/misc.S | 2 arch/ppc64/kernel/sys_ppc32.c | 239 ------------------------------------- arch/s390/kernel/compat_linux.c | 220 ---------------------------------- arch/s390/kernel/compat_wrapper.S | 10 - arch/s390/kernel/syscalls.S | 2 arch/sparc64/kernel/sys_sparc32.c | 226 ---------------------------------- arch/sparc64/kernel/systbls.S | 2 arch/x86_64/ia32/ia32entry.S | 2 arch/x86_64/ia32/sys_ia32.c | 227 ----------------------------------- fs/compat.c | 239 +++++++++++++++++++++++++++++++++++++ 13 files changed, 249 insertions(+), 1180 deletions(-)
===== arch/ia64/ia32/sys_ia32.c 1.96 vs edited =====
arch/ia64/ia32/sys_ia32.c +0 -170
@@ -2200,176 +2200,6 @@return sys_setresgid (srgid, segid, ssgid); } -/* Stuff for NFS server syscalls... */ -struct nfsctl_svc32 { -u16 svc32_port; -s32 svc32_nthreads; -}; - -struct nfsctl_client32 { -s8 cl32_ident[NFSCLNT_IDMAX +1 ]; -s32 cl32_naddr; -struct in_addr cl32_addrlist[NFSCLNT_ADDRMAX ]; -s32 cl32_fhkeytype; -s32 cl32_fhkeylen; -u8 cl32_fhkey[NFSCLNT_KEYMAX ]; -}; - -struct nfsctl_export32 { -s8 ex32_client[NFSCLNT_IDMAX +1 ]; -s8 ex32_path[NFS_MAXPATHLEN +1 ]; -compat_dev_t ex32_dev; -compat_ino_t ex32_ino; -s32 ex32_flags; -compat_uid_t ex32_anon_uid; -compat_gid_t ex32_anon_gid; -}; - -struct nfsctl_arg32 { -s32 ca32_version;/* safeguard */ -union { -struct nfsctl_svc32 u32_svc; -struct nfsctl_client32 u32_client; -struct nfsctl_export32 u32_export; -u32 u32_debug; - } u; -#define ca32_svc u.u32_svc -#define ca32_client u.u32_client -#define ca32_export u.u32_export -#define ca32_debug u.u32_debug -}; - -union nfsctl_res32 { -struct knfs_fh cr32_getfh; -u32 cr32_debug; -}; - -static int -nfs_svc32_trans (struct nfsctl_arg *karg,struct nfsctl_arg32 *arg32) -{ -int err; - - err =__get_user (karg->ca_version, &arg32->ca32_version); - err |=__get_user (karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port); - err |=__get_user (karg->ca_svc.svc_nthreads, - &arg32->ca32_svc.svc32_nthreads); -return err; -} - -static int -nfs_clnt32_trans (struct nfsctl_arg *karg,struct nfsctl_arg32 *arg32) -{ -int err; - - err =__get_user (karg->ca_version, &arg32->ca32_version); - err |=copy_from_user (&karg->ca_client.cl_ident[0 ], - &arg32->ca32_client.cl32_ident[0 ], -NFSCLNT_IDMAX ); - err |=__get_user (karg->ca_client.cl_naddr, - &arg32->ca32_client.cl32_naddr); - err |=copy_from_user (&karg->ca_client.cl_addrlist[0 ], - &arg32->ca32_client.cl32_addrlist[0 ], - (sizeof (struct in_addr ) *NFSCLNT_ADDRMAX )); - err |=__get_user (karg->ca_client.cl_fhkeytype, - &arg32->ca32_client.cl32_fhkeytype); - err |=__get_user (karg->ca_client.cl_fhkeylen, - &arg32->ca32_client.cl32_fhkeylen); - err |=copy_from_user (&karg->ca_client.cl_fhkey[0 ], - &arg32->ca32_client.cl32_fhkey[0 ], -NFSCLNT_KEYMAX ); -return err; -} - -static int -nfs_exp32_trans (struct nfsctl_arg *karg,struct nfsctl_arg32 *arg32) -{ -int err; - - err =__get_user (karg->ca_version, &arg32->ca32_version); - err |=copy_from_user (&karg->ca_export.ex_client[0 ], - &arg32->ca32_export.ex32_client[0 ], -NFSCLNT_IDMAX ); - err |=copy_from_user (&karg->ca_export.ex_path[0 ], - &arg32->ca32_export.ex32_path[0 ], -NFS_MAXPATHLEN ); - err |=__get_user (karg->ca_export.ex_dev, - &arg32->ca32_export.ex32_dev); - err |=__get_user (karg->ca_export.ex_ino, - &arg32->ca32_export.ex32_ino); - err |=__get_user (karg->ca_export.ex_flags, - &arg32->ca32_export.ex32_flags); - err |=__get_user (karg->ca_export.ex_anon_uid, - &arg32->ca32_export.ex32_anon_uid); - err |=__get_user (karg->ca_export.ex_anon_gid, - &arg32->ca32_export.ex32_anon_gid); -return err; -} - -static int -nfs_getfh32_res_trans (union nfsctl_res *kres,union nfsctl_res32 *res32) -{ -int err; - - err =copy_to_user (&res32->cr32_getfh, - &kres->cr_getfh, -sizeof (res32->cr32_getfh)); - err |=__put_user (kres->cr_debug, &res32->cr32_debug); -return err; -} - -int asmlinkage -sys32_nfsservctl (int cmd,struct nfsctl_arg32 *arg32,union nfsctl_res32 *res32) -{ -struct nfsctl_arg *karg =NULL ; -union nfsctl_res *kres =NULL ; -mm_segment_t oldfs; -int err; - - karg =kmalloc (sizeof (*karg),GFP_USER ); -if (!karg) -return -ENOMEM ; -if (res32) { - kres =kmalloc (sizeof (*kres),GFP_USER ); -if (!kres) { -kfree (karg); -return -ENOMEM ; - } - } -switch (cmd) { -case NFSCTL_SVC : - err =nfs_svc32_trans (karg, arg32); -break ; -case NFSCTL_ADDCLIENT : - err =nfs_clnt32_trans (karg, arg32); -break ; -case NFSCTL_DELCLIENT : - err =nfs_clnt32_trans (karg, arg32); -break ; -case NFSCTL_EXPORT : - err =nfs_exp32_trans (karg, arg32); -break ; -default : - err = -EINVAL ; -break ; - } -if (err) - goto done; - oldfs =get_fs (); -set_fs (KERNEL_DS ); - err =sys_nfsservctl (cmd, karg, kres); -set_fs (oldfs); - -if (!err && cmd ==NFSCTL_GETFS ) - err =nfs_getfh32_res_trans (kres, res32); - -done: -if (karg) -kfree (karg); -if (kres) -kfree (kres); -return err; -} -/* Handle adjtimex compatibility. */ struct timex32 {
===== arch/parisc/kernel/sys_parisc32.c 1.27 vs edited =====
arch/parisc/kernel/sys_parisc32.c +0 -88
94 lines not on this page · raw message
===== arch/parisc/kernel/syscall_table.S 1.6 vs edited =====
arch/parisc/kernel/syscall_table.S +1 -1
@@ -266,7 +266,7 @@ ENTRY_SAME(ni_syscall) /* query_module */ ENTRY_SAME(poll) /* structs contain pointers and an in_addr... */ - ENTRY_DIFF(nfsservctl) + ENTRY_COMP(nfsservctl) ENTRY_SAME(setresgid) /* 170 */ ENTRY_SAME(getresgid) ENTRY_SAME(prctl)
===== arch/ppc64/kernel/misc.S 1.76 vs edited =====
arch/ppc64/kernel/misc.S +1 -1
@@ -740,7 +740,7 @@ .llong .sys_getresuid /* 165 */ .llong .sys_ni_syscall /* old query_module syscall */ .llong .sys_poll - .llong .sys32_nfsservctl + .llong .compat_sys_nfsservctl .llong .sys_setresgid .llong .sys_getresgid /* 170 */ .llong .sys32_prctl
===== arch/ppc64/kernel/sys_ppc32.c 1.88 vs edited =====
arch/ppc64/kernel/sys_ppc32.c +0 -239
245 lines not on this page · raw message
===== arch/s390/kernel/compat_linux.c 1.21 vs edited =====
arch/s390/kernel/compat_linux.c +0 -220
226 lines not on this page · raw message
===== arch/s390/kernel/compat_wrapper.S 1.11 vs edited =====
arch/s390/kernel/compat_wrapper.S +5 -5
@@ -786,12 +786,12 @@ lgfr %r4,%r4 # long jg sys_poll # branch to system call - .globl sys32_nfsservctl_wrapper -sys32_nfsservctl_wrapper: + .globl compat_sys_nfsservctl_wrapper +compat_sys_nfsservctl_wrapper: lgfr %r2,%r2 # int - llgtr %r3,%r3 # struct nfsctl_arg_emu31 * - llgtr %r4,%r4 # union nfsctl_res_emu31 * - jg sys32_nfsservctl # branch to system call + llgtr %r3,%r3 # struct compat_nfsctl_arg* + llgtr %r4,%r4 # union compat_nfsctl_res* + jg compat_sys_nfsservctl # branch to system call .globl sys32_setresgid16_wrapper sys32_setresgid16_wrapper:
===== arch/s390/kernel/syscalls.S 1.11 vs edited =====
arch/s390/kernel/syscalls.S +1 -1
@@ -177,7 +177,7 @@ NI_SYSCALL /* for vm86 */ NI_SYSCALL /* old sys_query_module */ SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper) -SYSCALL(sys_nfsservctl,sys_nfsservctl,sys32_nfsservctl_wrapper) +SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper) SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */ SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */ SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
===== arch/sparc64/kernel/sys_sparc32.c 1.97 vs edited =====
arch/sparc64/kernel/sys_sparc32.c +0 -226
232 lines not on this page · raw message
===== arch/sparc64/kernel/systbls.S 1.54 vs edited =====
arch/sparc64/kernel/systbls.S +1 -1
@@ -69,7 +69,7 @@ .word compat_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep -/*250*/ .word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl +/*250*/ .word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, compat_sys_nfsservctl .word sys_ni_syscall, compat_clock_settime, compat_clock_gettime, compat_clock_getres, compat_clock_nanosleep /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, compat_timer_settime, compat_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
===== arch/x86_64/ia32/ia32entry.S 1.33 vs edited =====
arch/x86_64/ia32/ia32entry.S +1 -1
@@ -474,7 +474,7 @@ .quad sys32_vm86_warning /* vm86 */ .quad quiet_ni_syscall /* query_module */ .quad sys_poll - .quad sys32_nfsservctl + .quad compat_sys_nfsservctl .quad sys_setresgid16 /* 170 */ .quad sys_getresgid16 .quad sys_prctl
===== arch/x86_64/ia32/sys_ia32.c 1.59 vs edited =====
arch/x86_64/ia32/sys_ia32.c +0 -227
233 lines not on this page · raw message
===== fs/compat.c 1.24 vs edited =====
fs/compat.c +239 -0
242 lines not on this page · raw message