Fix up 32-bit compat for a bunch of syscalls
Subsystems (2)
A grab bag of fixes from testing glibc, o32 only, under both 32-bit and 64-bit kernels. Changes are:
- There is a generic compat_sys_wait4; use it.
- waitid needs compat routines for o32 (siginfo and rusage) and n32 (just rusage).
- timer_create needs a compat routine for both o32 and n32 (struct sigevent).
- rt_sigtimedwait can use the generic compat routine for o32, but not for n32, because n32 uses a 64-bit struct siginfo. I didn't actually test this one yet - I'll be doing n32 testing in a couple of weeks...
- For the same reason n32 should not use sys32_rt_sigqueueinfo.
- n32 does need compat versions of the other timer_* and clock_* functions however.
- o32 signal delivery was not handling SI_TIMER.
- waitid takes five arguments now, not four.
- PTRACE_GETEVENTMSG needs a compat wrapper since it writes a long to userspace.
With these, I get the same o32 glibc test results using a 32-bit or 64-bit kernel on my Sentosa. The only thing left which looks like a kernel bug is time-related; a bunch of the POSIX timers tests complain that timers trigger too soon.
Please apply if OK.
arch/mips/kernel/linux32.c +72 -67
@@ -215,81 +215,36 @@ sys32_readdir(unsigned int fd, void * direturn (n); } -struct rusage32 { -struct compat_timeval ru_utime; -struct compat_timeval ru_stime; -int ru_maxrss; -int ru_ixrss; -int ru_idrss; -int ru_isrss; -int ru_minflt; -int ru_majflt; -int ru_nswap; -int ru_inblock; -int ru_oublock; -int ru_msgsnd; -int ru_msgrcv; -int ru_nsignals; -int ru_nvcsw; -int ru_nivcsw; -}; -static int -put_rusage (struct rusage32 *ru,struct rusage *r) -{ -int err; +asmlinkage int compat_sys_wait4(compat_pid_t pid, unsigned int * stat_addr, +int options,struct compat_rusage * ru); -if (verify_area (VERIFY_WRITE , ru,sizeof *ru)) -return -EFAULT ; - - err =__put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); - err |=__put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); - err |=__put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); - err |=__put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); - err |=__put_user (r->ru_maxrss, &ru->ru_maxrss); - err |=__put_user (r->ru_ixrss, &ru->ru_ixrss); - err |=__put_user (r->ru_idrss, &ru->ru_idrss); - err |=__put_user (r->ru_isrss, &ru->ru_isrss); - err |=__put_user (r->ru_minflt, &ru->ru_minflt); - err |=__put_user (r->ru_majflt, &ru->ru_majflt); - err |=__put_user (r->ru_nswap, &ru->ru_nswap); - err |=__put_user (r->ru_inblock, &ru->ru_inblock); - err |=__put_user (r->ru_oublock, &ru->ru_oublock); - err |=__put_user (r->ru_msgsnd, &ru->ru_msgsnd); - err |=__put_user (r->ru_msgrcv, &ru->ru_msgrcv); - err |=__put_user (r->ru_nsignals, &ru->ru_nsignals); - err |=__put_user (r->ru_nvcsw, &ru->ru_nvcsw); - err |=__put_user (r->ru_nivcsw, &ru->ru_nivcsw); - -return err; +asmlinkage int +sys32_waitpid (compat_pid_t pid,unsigned int *stat_addr,int options) +{ +return compat_sys_wait4 (pid, stat_addr, options,NULL ); } -asmlinkage int -sys32_wait4 (compat_pid_t pid,unsigned int * stat_addr,int options, -struct rusage32 * ru) +asmlinkage long +sysn32_waitid (int which,compat_pid_t pid, +siginfo_t __user *uinfo,int options, +struct compat_rusage __user *uru) { -if (!ru) -return sys_wait4 (pid, stat_addr, options,NULL ); -else { -struct rusage r; -int ret; -unsigned int status; -mm_segment_t old_fs =get_fs (); +struct rusage ru; +long ret; +mm_segment_t old_fs =get_fs (); -set_fs (KERNEL_DS ); - ret =sys_wait4 (pid, stat_addr ? &status :NULL , options, &r); -set_fs (old_fs); -if (put_rusage (ru, &r))return -EFAULT ; -if (stat_addr &&put_user (status, stat_addr)) -return -EFAULT ; +set_fs (KERNEL_DS ); + ret =sys_waitid (which, pid, uinfo, options, + uru ? (struct rusage __user *) &ru :NULL ); +set_fs (old_fs); + +if (ret <0 || uinfo->si_signo ==0 )return ret; - } -} -asmlinkage int -sys32_waitpid (compat_pid_t pid,unsigned int *stat_addr,int options) -{ -return sys32_wait4 (pid, stat_addr, options,NULL ); +if (uru) + ret =put_compat_rusage (&ru, uru); +return ret; }struct sysinfo32 {
@@ -1496,3 +1451,53 @@ _sys32_clone(unsigned long __dummy0,return do_fork (clone_flags, newsp, ®s,0 , parent_tidptr, child_tidptr); } + +struct sigevent32 { +u32 sigev_value; +u32 sigev_signo; +u32 sigev_notify; +u32 payload[(64 /4 ) -3 ]; +}; + +extern asmlinkage long +sys_timer_create (clockid_t which_clock, +struct sigevent __user *timer_event_spec, +timer_t __user * created_timer_id); + +long +sys32_timer_create (u32 clock,struct sigevent32 __user *se32,timer_t __user *timer_id) +{ +struct sigevent __user *p =NULL ; +if (se32) { +struct sigevent se; + p =compat_alloc_user_space (sizeof (struct sigevent )); +memset (&se,0 ,sizeof (struct sigevent )); +if (get_user (se.sigev_value.sival_int, &se32->sigev_value) || +__get_user (se.sigev_signo, &se32->sigev_signo) || +__get_user (se.sigev_notify, &se32->sigev_notify) || +__copy_from_user (&se._sigev_un._pad, &se32->payload, +sizeof (se32->payload)) || +copy_to_user (p, &se,sizeof (se))) +return -EFAULT ; + } +return sys_timer_create (clock, p, timer_id); +} + +asmlinkage long +sysn32_rt_sigtimedwait (const sigset_t __user *uthese, +siginfo_t __user *uinfo, +const struct compat_timespec __user *uts32, +size_t sigsetsize) +{ +struct timespec __user *uts =NULL ; + +if (uts32) { +struct timespec ts; + uts =compat_alloc_user_space (sizeof (struct timespec )); +if (get_user (ts.tv_sec, &uts32->tv_sec) || +get_user (ts.tv_nsec, &uts32->tv_nsec) || +copy_to_user (uts, &ts,sizeof (ts))) +return -EFAULT ; + } +return sys_rt_sigtimedwait (uthese, uinfo, uts, sigsetsize); +}
arch/mips/kernel/scall64-o32.S +3 -3
@@ -316,7 +316,7 @@ sys_call_table: PTR sys_vhangup PTR sys_ni_syscall /* was sys_idle */ PTR sys_ni_syscall /* sys_vm86 */ - PTR sys32_wait4 + PTR compat_sys_wait4 PTR sys_swapoff /* 4115 */ PTR sys32_sysinfo PTR sys32_ipc
@@ -459,7 +459,7 @@ sys_call_table: PTR sys_fadvise64_64 PTR compat_sys_statfs64 /* 4255 */ PTR compat_sys_fstatfs64 - PTR sys_timer_create + PTR sys32_timer_create PTR compat_sys_timer_settime PTR compat_sys_timer_gettime PTR sys_timer_getoverrun /* 4260 */
@@ -480,7 +480,7 @@ sys_call_table: PTR compat_sys_mq_notify /* 4275 */ PTR compat_sys_mq_getsetattr PTR sys_ni_syscall /* sys_vserver */ - PTR sys_waitid + PTR sys32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ PTR sys_request_key
arch/mips/kernel/scall64-n32.S +11 -11
@@ -176,7 +176,7 @@ EXPORT(sysn32_call_table) PTR sys_fork PTR sys32_execve PTR sys_exit - PTR sys32_wait4 + PTR compat_sys_wait4 PTR sys_kill /* 6060 */ PTR sys32_newuname PTR sys_semget
@@ -243,8 +243,8 @@ EXPORT(sysn32_call_table) PTR sys_capget PTR sys_capset PTR sys32_rt_sigpending /* 6125 */ - PTR compat_sys_rt_sigtimedwait - PTR sys32_rt_sigqueueinfo + PTR sysn32_rt_sigtimedwait + PTR sys_rt_sigqueueinfo PTR sys32_rt_sigsuspend PTR sys32_sigaltstack PTR compat_sys_utime /* 6130 */
@@ -337,15 +337,15 @@ EXPORT(sysn32_call_table) PTR compat_sys_statfs64 PTR compat_sys_fstatfs64 PTR sys_sendfile64 - PTR sys_timer_create /* 6220 */ - PTR sys_timer_settime - PTR sys_timer_gettime + PTR sys32_timer_create /* 6220 */ + PTR compat_sys_timer_settime + PTR compat_sys_timer_gettime PTR sys_timer_getoverrun PTR sys_timer_delete - PTR sys_clock_settime /* 6225 */ - PTR sys_clock_gettime - PTR sys_clock_getres - PTR sys_clock_nanosleep + PTR compat_sys_clock_settime /* 6225 */ + PTR compat_sys_clock_gettime + PTR compat_sys_clock_getres + PTR compat_sys_clock_nanosleep PTR sys_tgkill PTR compat_sys_utimes /* 6230 */ PTR sys_ni_syscall /* sys_mbind */
@@ -358,7 +358,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_mq_notify PTR compat_sys_mq_getsetattr PTR sys_ni_syscall /* 6240, sys_vserver */ - PTR sys_waitid + PTR sysn32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key PTR sys_request_key
arch/mips/kernel/signal32.c +36 -2
@@ -81,8 +81,10 @@ typedef struct compat_siginfo {/* POSIX.1b timers */ struct { -unsigned int _timer1; -unsigned int _timer2; +timer_t _tid;/* timer id */ +int _overrun;/* overrun count */ +sigval_t32 _sigval;/* same as below */ +int _sys_private;/* not to be passed to user */ } _timer;/* POSIX.1b signals */
@@ -416,6 +418,11 @@ int copy_siginfo_to_user32(compat_siginf err |=__copy_to_user (&to->_sifields._pad, &from->_sifields._pad,SI_PAD_SIZE ); else {switch (from->si_code >>16 ) { +case __SI_TIMER >>16 : + err |=__put_user (from->si_tid, &to->si_tid); + err |=__put_user (from->si_overrun, &to->si_overrun); + err |=__put_user (from->si_int, &to->si_int); +break ;case __SI_CHLD >>16 : err |=__put_user (from->si_utime, &to->si_utime); err |=__put_user (from->si_stime, &to->si_stime);
@@ -908,3 +915,30 @@ asmlinkage int sys32_rt_sigqueueinfo(intset_fs (old_fs);return ret; } + +asmlinkage long +sys32_waitid (int which,compat_pid_t pid, +compat_siginfo_t __user *uinfo,int options, +struct compat_rusage __user *uru) +{ +siginfo_t info; +struct rusage ru; +long ret; +mm_segment_t old_fs =get_fs (); + + info.si_signo =0 ; +set_fs (KERNEL_DS ); + ret =sys_waitid (which, pid, (siginfo_t __user *) &info, options, + uru ? (struct rusage __user *) &ru :NULL ); +set_fs (old_fs); + +if (ret <0 || info.si_signo ==0 ) +return ret; + +if (uru && (ret =put_compat_rusage (&ru, uru))) +return ret; + +BUG_ON (info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; +return copy_siginfo_to_user32 (uinfo, &info); +}
arch/mips/kernel/scall32-o32.S +1 -1
@@ -618,7 +618,7 @@ einval: li v0, -EINVAL sys sys_mq_notify 2 /* 4275 */ sys sys_mq_getsetattr 3 sys sys_ni_syscall 0 /* sys_vserver */ - sys sys_waitid 4 + sys sys_waitid 5 sys sys_ni_syscall 0 /* available, was setaltroot */ sys sys_add_key 5 sys sys_request_key 4
arch/mips/kernel/ptrace32.c +5 -0
@@ -277,6 +277,11 @@ asmlinkage int sys32_ptrace(int request, ret =ptrace_detach (child, data);break ; +case PTRACE_GETEVENTMSG : + ret =put_user (child->ptrace_message, + (unsigned int __user *) (unsigned long ) data); +break ; +default : ret =ptrace_request (child, request, addr, data);break ;
Signature · 2 lines
Daniel Jacobowitz CodeSourcery, LLC