diff options
| author | Zou Nanhai <nanhai.zou@intel.com> | 2005-01-04 05:36:02 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-01-04 05:36:02 -0800 |
| commit | 4b36077f9cbc7bd58dc616a778b3290f1ea43c98 (patch) | |
| tree | f99f85157f3cbdb9925729429a5aba37bcc533da | |
| parent | effe830dd3b5af86b8b76dd298ba1d5d8b08f530 (diff) | |
[PATCH] compat: sigtimedwait
- Merge sys32_rt_sigtimedwait function in X86_64, IA64, PPC64, MIPS,
SPARC64, S390 32 bit layer into 1 compat_rt_sigtimedwait function. It will
also fix a bug of copy wrong information to 32 bit userspace siginfo
structure on X86_64, IA64 and SPARC64 when calling sigtimedwait on 32 bit
layer.
- Change all name the of siginfo_t32 structure in X86_64, IA64, MIPS,
SPARC64 and S390 to the name compat_siginfo_t as used in PPC64.
- Patch introduced a macro __COMPAT_ENDIAN_SWAP__ in
include/asm-mips/compat.h when MIPS kernel is compiled in little-endian
mode. This macro is used to do byte swapping in function
sigset_from_compat.
- This patch is only tested on X86_64 and IA_64.
Signed-off-by: Zou Nan hai <Nanhai.zou@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
26 files changed, 156 insertions, 433 deletions
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 1b064f7c8668..eb922619889a 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -387,7 +387,7 @@ ia32_syscall_table: data8 sys32_rt_sigaction data8 sys32_rt_sigprocmask /* 175 */ data8 sys_rt_sigpending - data8 sys32_rt_sigtimedwait + data8 compat_rt_sigtimedwait data8 sys32_rt_sigqueueinfo data8 sys32_rt_sigsuspend data8 sys32_pread /* 180 */ diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index 7f2fc27045e9..828a38a2249b 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -59,19 +59,19 @@ struct rt_sigframe_ia32 int sig; int pinfo; int puc; - siginfo_t32 info; + compat_siginfo_t info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8]; }; int -copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 __user *from) +copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) { unsigned long tmp; int err; - if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t32))) + if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) return -EFAULT; err = __get_user(to->si_signo, &from->si_signo); @@ -110,12 +110,12 @@ copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 __user *from) } int -copy_siginfo_to_user32 (siginfo_t32 __user *to, siginfo_t *from) +copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) { unsigned int addr; int err; - if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -589,34 +589,7 @@ sys32_rt_sigprocmask (int how, compat_sigset_t __user *set, compat_sigset_t __us } asmlinkage long -sys32_rt_sigtimedwait (compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo, - struct compat_timespec __user *uts, unsigned int sigsetsize) -{ - mm_segment_t old_fs = get_fs(); - struct timespec t; - siginfo_t info; - sigset_t s; - int ret; - - if (copy_from_user(&s.sig, uthese, sizeof(compat_sigset_t))) - return -EFAULT; - if (uts && get_compat_timespec(&t, uts)) - return -EFAULT; - set_fs(KERNEL_DS); - ret = sys_rt_sigtimedwait((sigset_t __user *) &s, - uinfo ? (siginfo_t __user *) &info : NULL, - uts ? (struct timespec __user *) &t : NULL, - sigsetsize); - set_fs(old_fs); - if (ret >= 0 && uinfo) { - if (copy_siginfo_to_user32(uinfo, &info)) - return -EFAULT; - } - return ret; -} - -asmlinkage long -sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 __user *uinfo) +sys32_rt_sigqueueinfo (int pid, int sig, compat_siginfo_t __user *uinfo) { mm_segment_t old_fs = get_fs(); siginfo_t info; diff --git a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h index 8012513e0160..ebdd4e20bb0d 100644 --- a/arch/ia64/ia32/ia32priv.h +++ b/arch/ia64/ia32/ia32priv.h @@ -232,7 +232,7 @@ typedef union sigval32 { #define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3) -typedef struct siginfo32 { +typedef struct compat_siginfo { int si_signo; int si_errno; int si_code; @@ -282,7 +282,7 @@ typedef struct siginfo32 { int _fd; } _sigpoll; } _sifields; -} siginfo_t32; +} compat_siginfo_t; typedef struct sigevent32 { sigval_t32 sigev_value; @@ -559,10 +559,6 @@ struct user_regs_struct32 { extern int save_ia32_fpstate (struct task_struct *, struct ia32_user_i387_struct __user *); extern int save_ia32_fpxstate (struct task_struct *, struct ia32_user_fxsr_struct __user *); -/* Prototypes for use in sys_ia32.c */ -int copy_siginfo_to_user32 (siginfo_t32 __user *to, siginfo_t *from); -int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 __user *from); - #endif /* !CONFIG_IA32_SUPPORT */ #endif /* _ASM_IA64_IA32_PRIV_H */ diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 5331a42e1957..009e40e500ea 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -2641,7 +2641,7 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, } asmlinkage long sys32_waitid(int which, compat_pid_t pid, - siginfo_t32 __user *uinfo, int options, + compat_siginfo_t __user *uinfo, int options, struct compat_rusage __user *uru) { siginfo_t info; diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 0d49ab1c2385..6485e741fb98 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -243,7 +243,7 @@ EXPORT(sysn32_call_table) PTR sys_capget PTR sys_capset PTR sys32_rt_sigpending /* 6125 */ - PTR sys32_rt_sigtimedwait + PTR compat_rt_sigtimedwait PTR sys32_rt_sigqueueinfo PTR sys32_rt_sigsuspend PTR sys32_sigaltstack diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index eda6c2d78b19..5e40ce0a20c9 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -420,7 +420,7 @@ sys_call_table: PTR sys32_rt_sigaction PTR sys32_rt_sigprocmask /* 4195 */ PTR sys32_rt_sigpending - PTR sys32_rt_sigtimedwait + PTR compat_rt_sigtimedwait PTR sys32_rt_sigqueueinfo PTR sys32_rt_sigsuspend PTR sys32_pread /* 4200 */ diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 12c2104247e4..c7879c225c97 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -37,7 +37,7 @@ typedef union sigval32 { s32 sival_ptr; } sigval_t32; -typedef struct siginfo32 { +typedef struct compat_siginfo{ int si_signo; int si_code; int si_errno; @@ -93,7 +93,7 @@ typedef struct siginfo32 { } _rt; } _sifields; -} siginfo_t32; +} compat_siginfo_t; /* * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... @@ -389,15 +389,15 @@ struct sigframe { struct rt_sigframe32 { u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_code[2]; /* signal trampoline */ - struct siginfo32 rs_info; + struct compat_siginfo_t rs_info; struct ucontext32 rs_uc; }; -static int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) +int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from) { int err; - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -677,7 +677,7 @@ static inline void setup_rt_frame(struct k_sigaction * ka, err |= __put_user(0x0000000c , frame->rs_code + 1); flush_cache_sigtramp((unsigned long) frame->rs_code); - /* Convert (siginfo_t -> siginfo_t32) and copy to user. */ + /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ err |= copy_siginfo_to_user32(&frame->rs_info, info); /* Create the ucontext. */ @@ -890,98 +890,7 @@ asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset, return ret; } -asmlinkage int sys32_rt_sigtimedwait(compat_sigset_t *uthese, - siginfo_t32 *uinfo, struct compat_timespec *uts, - compat_time_t sigsetsize) -{ - int ret, sig; - sigset_t these; - compat_sigset_t these32; - struct timespec ts; - siginfo_t info; - long timeout = 0; - - /* - * As the result of a brainfarting competition a few years ago the - * size of sigset_t for the 32-bit kernel was choosen to be 128 bits - * but nothing so far is actually using that many, 64 are enough. So - * for now we just drop the high bits. - */ - if (copy_from_user (&these32, uthese, sizeof(compat_old_sigset_t))) - return -EFAULT; - - switch (_NSIG_WORDS) { -#ifdef __MIPSEB__ - case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32); - case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32); - case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32); - case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32); -#endif -#ifdef __MIPSEL__ - case 4: these.sig[3] = these32.sig[7] | (((long)these32.sig[6]) << 32); - case 3: these.sig[2] = these32.sig[5] | (((long)these32.sig[4]) << 32); - case 2: these.sig[1] = these32.sig[3] | (((long)these32.sig[2]) << 32); - case 1: these.sig[0] = these32.sig[1] | (((long)these32.sig[0]) << 32); -#endif - } - - /* - * Invert the set of allowed signals to get those we - * want to block. - */ - sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); - signotset(&these); - - if (uts) { - if (get_user (ts.tv_sec, &uts->tv_sec) || - get_user (ts.tv_nsec, &uts->tv_nsec)) - return -EINVAL; - if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 - || ts.tv_sec < 0) - return -EINVAL; - } - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - if (!sig) { - /* None ready -- temporarily unblock those we're interested - in so that we'll be awakened when they arrive. */ - sigset_t oldblocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &these); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - timeout = MAX_SCHEDULE_TIMEOUT; - if (uts) - timeout = (timespec_to_jiffies(&ts) - + (ts.tv_sec || ts.tv_nsec)); - - current->state = TASK_INTERRUPTIBLE; - timeout = schedule_timeout(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - current->blocked = oldblocked; - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); - - if (sig) { - ret = sig; - if (uinfo) { - if (copy_siginfo_to_user32(uinfo, &info)) - ret = -EFAULT; - } - } else { - ret = -EAGAIN; - if (timeout) - ret = -EINTR; - } - - return ret; -} - -asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) +asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t *uinfo) { siginfo_t info; int ret; diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index e93e29a1a902..a795ae320b37 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -863,7 +863,7 @@ _GLOBAL(sys_call_table32) .llong .sys32_rt_sigaction .llong .sys32_rt_sigprocmask .llong .sys32_rt_sigpending /* 175 */ - .llong .sys32_rt_sigtimedwait + .llong .compat_rt_sigtimedwait .llong .sys32_rt_sigqueueinfo .llong .ppc32_rt_sigsuspend .llong .sys32_pread64 diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index bdc0d624b86f..145eac7ef8f4 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -72,7 +72,7 @@ struct sigregs32 { * */ struct rt_sigframe32 { - struct compat_siginfo info; + compat_siginfo_t info; struct ucontext32 uc; /* * Programs using the rs6000/xcoff abi can save up to 19 gp @@ -341,7 +341,6 @@ long sys32_sigaction(int sig, struct old_sigaction32 __user *act, * sigpending sys32_rt_sigpending * sigprocmask sys32_rt_sigprocmask * sigreturn sys32_rt_sigreturn - * sigtimedwait sys32_rt_sigtimedwait * sigqueueinfo sys32_rt_sigqueueinfo * sigsuspend sys32_rt_sigsuspend * @@ -445,9 +444,9 @@ long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) } -static long copy_siginfo_to_user32(compat_siginfo_t __user *d, siginfo_t *s) +int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s) { - long err; + int err; if (!access_ok (VERIFY_WRITE, d, sizeof(*d))) return -EFAULT; @@ -500,35 +499,6 @@ static long copy_siginfo_to_user32(compat_siginfo_t __user *d, siginfo_t *s) return err; } -long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, compat_siginfo_t __user *uinfo, - struct compat_timespec __user *uts, compat_size_t sigsetsize) -{ - sigset_t s; - compat_sigset_t s32; - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs(); - siginfo_t info; - - if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t))) - return -EFAULT; - sigset_from_compat(&s, &s32); - if (uts && get_compat_timespec(&t, uts)) - return -EFAULT; - set_fs(KERNEL_DS); - /* The __user pointer casts are valid because of the set_fs() */ - ret = sys_rt_sigtimedwait((sigset_t __user *) &s, - uinfo ? (siginfo_t __user *) &info : NULL, - uts ? (struct timespec __user *) &t : NULL, - sigsetsize); - set_fs(old_fs); - if (ret >= 0 && uinfo) { - if (copy_siginfo_to_user32(uinfo, &info)) - return -EFAULT; - } - return ret; -} - /* * Note: it is necessary to treat pid and sig as unsigned ints, with the * corresponding cast to a signed int to insure that the proper conversion diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 01f57183d9ba..98de3fea7380 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -634,92 +634,8 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set, return ret; } -extern int -copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from); - -asmlinkage long -sys32_rt_sigtimedwait(compat_sigset_t *uthese, siginfo_t32 *uinfo, - struct compat_timespec *uts, size_t sigsetsize) -{ - int ret, sig; - sigset_t these; - compat_sigset_t these32; - struct timespec ts; - siginfo_t info; - long timeout = 0; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user (&these32, uthese, sizeof(compat_sigset_t))) - return -EFAULT; - - switch (_NSIG_WORDS) { - case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32); - case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32); - case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32); - case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32); - } - - /* - * Invert the set of allowed signals to get those we - * want to block. - */ - sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); - signotset(&these); - - if (uts) { - if (get_compat_timespec(&ts, uts)) - return -EINVAL; - if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 - || ts.tv_sec < 0) - return -EINVAL; - } - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - if (!sig) { - /* None ready -- temporarily unblock those we're interested - in so that we'll be awakened when they arrive. */ - current->real_blocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &these); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - timeout = MAX_SCHEDULE_TIMEOUT; - if (uts) - timeout = (timespec_to_jiffies(&ts) - + (ts.tv_sec || ts.tv_nsec)); - - current->state = TASK_INTERRUPTIBLE; - timeout = schedule_timeout(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - current->blocked = current->real_blocked; - siginitset(¤t->real_blocked, 0); - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); - - if (sig) { - ret = sig; - if (uinfo) { - if (copy_siginfo_to_user32(uinfo, &info)) - ret = -EFAULT; - } - } else { - ret = -EAGAIN; - if (timeout) - ret = -EINTR; - } - - return ret; -} - asmlinkage long -sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo) +sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) { siginfo_t info; int ret; diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 48209a81ae9f..365d10be8390 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -34,7 +34,7 @@ typedef union sigval32 { __u32 sival_ptr; } sigval_t32; -typedef struct siginfo32 { +typedef struct compat_siginfo { int si_signo; int si_errno; int si_code; @@ -82,7 +82,7 @@ typedef struct siginfo32 { int _fd; } _sigpoll; } _sifields; -} siginfo_t32; +} compat_siginfo_t; /* * How these fields are to be accessed. @@ -214,7 +214,4 @@ struct sigevent32 { } _sigev_un; }; -extern int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from); -extern int copy_siginfo_from_user32(siginfo_t *to, siginfo_t32 __user *from); - #endif /* _ASM_S390X_S390_H */ diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index f29bcb856e58..1b8b580ba79e 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -48,17 +48,17 @@ typedef struct { __u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; __u8 retcode[S390_SYSCALL_SIZE]; - struct siginfo32 info; + compat_siginfo_t info; struct ucontext32 uc; } rt_sigframe32; asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); -int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) +int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -106,12 +106,12 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) return err; } -int copy_siginfo_from_user32(siginfo_t *to, siginfo_t32 __user *from) +int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { int err; u32 tmp; - if (!access_ok (VERIFY_READ, from, sizeof(siginfo_t32))) + if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t))) return -EFAULT; err = __get_user(to->si_signo, &from->si_signo); diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index fdb72dbb43ee..9b07d13cd8d1 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -840,13 +840,13 @@ sys32_rt_sigpending_wrapper: llgfr %r3,%r3 # size_t jg sys32_rt_sigpending # branch to system call - .globl sys32_rt_sigtimedwait_wrapper -sys32_rt_sigtimedwait_wrapper: + .globl compat_rt_sigtimedwait_wrapper +compat_rt_sigtimedwait_wrapper: llgtr %r2,%r2 # const sigset_emu31_t * llgtr %r3,%r3 # siginfo_emu31_t * llgtr %r4,%r4 # const struct compat_timespec * llgfr %r5,%r5 # size_t - jg sys32_rt_sigtimedwait # branch to system call + jg compat_rt_sigtimedwait # branch to system call .globl sys32_rt_sigqueueinfo_wrapper sys32_rt_sigqueueinfo_wrapper: diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 2df9d1af0940..5755530a5079 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -559,13 +559,13 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) case PTRACE_GETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; - return copy_siginfo_to_user32((siginfo_t32 __user *) data, + return copy_siginfo_to_user32((compat_siginfo_t __user *) data, child->last_siginfo); case PTRACE_SETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; return copy_siginfo_from_user32(child->last_siginfo, - (siginfo_t32 __user *) data); + (compat_siginfo_t __user *) data); } return ptrace_request(child, request, addr, data); } diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index f5207d91670c..094d7527740f 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -185,7 +185,7 @@ SYSCALL(sys_rt_sigreturn_glue,sys_rt_sigreturn_glue,sys32_rt_sigreturn_glue) SYSCALL(sys_rt_sigaction,sys_rt_sigaction,sys32_rt_sigaction_wrapper) SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper) /* 175 */ SYSCALL(sys_rt_sigpending,sys_rt_sigpending,sys32_rt_sigpending_wrapper) -SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,sys32_rt_sigtimedwait_wrapper) +SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_rt_sigtimedwait_wrapper) SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper) SYSCALL(sys_rt_sigsuspend_glue,sys_rt_sigsuspend_glue,sys32_rt_sigsuspend_glue) SYSCALL(sys_pread64,sys_pread64,sys32_pread64_wrapper) /* 180 */ diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index ab266049499e..4e2519fa0c1c 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -86,7 +86,7 @@ struct new_signal_frame32 { __siginfo_fpu_t fpu_state; }; -struct siginfo32 { +typedef struct compat_siginfo{ int si_signo; int si_errno; int si_code; @@ -136,11 +136,11 @@ struct siginfo32 { int _fd; } _sigpoll; } _sifields; -}; +}compat_siginfo_t; struct rt_signal_frame32 { struct sparc_stackf32 ss; - struct siginfo32 info; + compat_siginfo_t info; struct pt_regs32 regs; compat_sigset_t mask; /* __siginfo_fpu32_t * */ u32 fpu_save; @@ -157,11 +157,11 @@ struct rt_signal_frame32 { #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) -int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from) +int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; - if (!access_ok(VERIFY_WRITE, to, sizeof(struct siginfo32))) + if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -210,9 +210,9 @@ int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from) /* CAUTION: This is just a very minimalist implementation for the * sake of compat_sys_rt_sigqueueinfo() */ -int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from) +int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { - if (!access_ok(VERIFY_WRITE, from, sizeof(struct siginfo32))) + if (!access_ok(VERIFY_WRITE, from, sizeof(compat_siginfo_t))) return -EFAULT; if (copy_from_user(to, from, 3*sizeof(int)) || diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 28014dc74194..f2314232f5f8 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1044,99 +1044,14 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set, return ret; } -asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, - struct siginfo32 __user *uinfo, - struct compat_timespec __user *uts, - compat_size_t sigsetsize) -{ - int ret, sig; - sigset_t these; - compat_sigset_t these32; - struct timespec ts; - siginfo_t info; - long timeout = 0; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user (&these32, uthese, sizeof(compat_sigset_t))) - return -EFAULT; - - switch (_NSIG_WORDS) { - case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32); - case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32); - case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32); - case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32); - } - - /* - * Invert the set of allowed signals to get those we - * want to block. - */ - sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); - signotset(&these); - - if (uts) { - if (get_compat_timespec(&ts, uts)) - return -EINVAL; - if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 - || ts.tv_sec < 0) - return -EINVAL; - } - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - if (!sig) { - timeout = MAX_SCHEDULE_TIMEOUT; - if (uts) - timeout = (timespec_to_jiffies(&ts) - + (ts.tv_sec || ts.tv_nsec)); - - if (timeout) { - /* None ready -- temporarily unblock those we're - * interested while we are sleeping in so that we'll - * be awakened when they arrive. */ - current->real_blocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &these); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - current->state = TASK_INTERRUPTIBLE; - timeout = schedule_timeout(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - current->blocked = current->real_blocked; - siginitset(¤t->real_blocked, 0); - recalc_sigpending(); - } - } - spin_unlock_irq(¤t->sighand->siglock); - - if (sig) { - ret = sig; - if (uinfo) { - if (copy_siginfo_to_user32(uinfo, &info)) - ret = -EFAULT; - } - } else { - ret = -EAGAIN; - if (timeout) - ret = -EINTR; - } - - return ret; -} - asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, - struct siginfo32 __user *uinfo) + struct compat_siginfo __user *uinfo) { siginfo_t info; int ret; mm_segment_t old_fs = get_fs(); - if (copy_siginfo_to_kernel32(&info, uinfo)) + if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs (KERNEL_DS); @@ -1739,8 +1654,8 @@ sys32_timer_create(u32 clock, struct sigevent32 __user *se32, } asmlinkage long compat_sys_waitid(u32 which, u32 pid, - struct siginfo32 __user *uinfo, u32 options, - struct compat_rusage __user *uru) + struct compat_siginfo __user *uinfo, + u32 options, struct compat_rusage __user *uru) { siginfo_t info; struct rusage ru; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index b3f1453172fe..bfa45ffa126a 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -41,7 +41,7 @@ sys_call_table32: /*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid .word sys_fsync, sys32_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*100*/ .word sys32_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 + .word compat_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 sys32_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd /*120*/ .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c index 5fb7d173b913..16854c4faa64 100644 --- a/arch/x86_64/ia32/ia32_signal.c +++ b/arch/x86_64/ia32/ia32_signal.c @@ -44,10 +44,10 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); void signal_fault(struct pt_regs *regs, void __user *frame, char *where); -int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from) +int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please make sure that @@ -95,11 +95,11 @@ int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from) return err; } -int ia32_copy_siginfo_from_user(siginfo_t *to, siginfo_t32 __user *from) +int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { int err; u32 ptr32; - if (!access_ok (VERIFY_READ, from, sizeof(siginfo_t32))) + if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t))) return -EFAULT; err = __get_user(to->si_signo, &from->si_signo); @@ -188,7 +188,7 @@ struct rt_sigframe int sig; u32 pinfo; u32 puc; - struct siginfo32 info; + compat_siginfo_t info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8]; @@ -536,7 +536,7 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } err |= __put_user((u32)(u64)&frame->info, &frame->pinfo); err |= __put_user((u32)(u64)&frame->uc, &frame->puc); - err |= ia32_copy_siginfo_to_user(&frame->info, info); + err |= copy_siginfo_to_user32(&frame->info, info); if (err) goto give_sigsegv; diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index c260192601af..4210fa0e6918 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -479,7 +479,7 @@ ia32_sys_call_table: .quad sys32_rt_sigaction .quad sys32_rt_sigprocmask /* 175 */ .quad sys32_rt_sigpending - .quad sys32_rt_sigtimedwait + .quad compat_rt_sigtimedwait .quad sys32_rt_sigqueueinfo .quad stub32_rt_sigsuspend .quad sys32_pread /* 180 */ diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 1ddf75a2d394..ffa25d474aed 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -628,53 +628,14 @@ sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) return ret; } - -asmlinkage long -sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo, - struct compat_timespec __user *uts, compat_size_t sigsetsize) -{ - sigset_t s; - compat_sigset_t s32; - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs(); - siginfo_t info; - - if (copy_from_user (&s32, uthese, sizeof(compat_sigset_t))) - return -EFAULT; - switch (_NSIG_WORDS) { - case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); - } - if (uts && get_compat_timespec(&t, uts)) - return -EFAULT; - if (uinfo) { - /* stop data leak to user space in case of structure fill mismatch - * between sys_rt_sigtimedwait & ia32_copy_siginfo_to_user. - */ - memset(&info, 0, sizeof(info)); - } - set_fs (KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL, - sigsetsize); - set_fs (old_fs); - if (ret >= 0 && uinfo) { - if (ia32_copy_siginfo_to_user(uinfo, &info)) - return -EFAULT; - } - return ret; -} - asmlinkage long -sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo) +sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) { siginfo_t info; int ret; mm_segment_t old_fs = get_fs(); - if (ia32_copy_siginfo_from_user(&info, uinfo)) + if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, &info); @@ -1000,7 +961,7 @@ asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, } asmlinkage long sys32_waitid(int which, compat_pid_t pid, - siginfo_t32 __user *uinfo, int options, + compat_siginfo_t __user *uinfo, int options, struct compat_rusage __user *uru) { siginfo_t info; @@ -1022,7 +983,7 @@ asmlinkage long sys32_waitid(int which, compat_pid_t pid, BUG_ON(info.si_code & __SI_MASK); info.si_code |= __SI_CHLD; - return ia32_copy_siginfo_to_user(uinfo, &info); + return copy_siginfo_to_user32(uinfo, &info); } /* diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h index 38b2116c78d2..dce92079e7fc 100644 --- a/include/asm-mips/compat.h +++ b/include/asm-mips/compat.h @@ -137,5 +137,8 @@ static inline void *compat_alloc_user_space(long len) return (void *) (regs->regs[29] - len); } +#if defined (__MIPSEL__) +#define __COMPAT_ENDIAN_SWAP__ 1 +#endif #endif /* _ASM_COMPAT_H */ diff --git a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h index 94b272f5d1b3..49952c6a23eb 100644 --- a/include/asm-sparc64/siginfo.h +++ b/include/asm-sparc64/siginfo.h @@ -24,7 +24,7 @@ typedef union sigval32 { u32 sival_ptr; } sigval_t32; -struct siginfo32; +struct compat_siginfo; #endif /* CONFIG_COMPAT */ @@ -56,9 +56,6 @@ typedef struct sigevent32 { } _sigev_un; } sigevent_t32; -extern int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from); -extern int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from); - #endif /* CONFIG_COMPAT */ #endif /* __KERNEL__ */ diff --git a/include/asm-x86_64/ia32.h b/include/asm-x86_64/ia32.h index 73319a9a8ca5..c0a7717923ed 100644 --- a/include/asm-x86_64/ia32.h +++ b/include/asm-x86_64/ia32.h @@ -78,7 +78,7 @@ struct stat64 { unsigned long long st_ino; } __attribute__((packed)); -typedef struct siginfo32 { +typedef struct compat_siginfo{ int si_signo; int si_errno; int si_code; @@ -128,7 +128,7 @@ typedef struct siginfo32 { int _fd; } _sigpoll; } _sifields; -} siginfo_t32; +} compat_siginfo_t; struct sigframe32 { @@ -145,7 +145,7 @@ struct rt_sigframe32 int sig; u32 pinfo; u32 puc; - struct siginfo32 info; + compat_siginfo_t info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; }; @@ -165,8 +165,6 @@ struct siginfo_t; int do_get_thread_area(struct thread_struct *t, struct user_desc __user *info); int do_set_thread_area(struct thread_struct *t, struct user_desc __user *info); int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs); -int ia32_copy_siginfo_from_user(siginfo_t *to, siginfo_t32 __user *from); -int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from); #endif #endif /* !CONFIG_IA32_SUPPORT */ diff --git a/include/linux/compat.h b/include/linux/compat.h index 56d5582abfe2..a62f5c960c75 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -143,6 +143,8 @@ long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask, unsigned long bitmap_size); long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, unsigned long bitmap_size); - +struct compat_siginfo; +int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from); +int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from); #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ diff --git a/kernel/compat.c b/kernel/compat.c index 48fc40aec712..48ee147c1343 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -682,6 +682,92 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, return 0; } +void +sigset_from_compat (sigset_t *set, compat_sigset_t *compat) +{ + switch (_NSIG_WORDS) { +#if defined (__COMPAT_ENDIAN_SWAP__) + case 4: set->sig[3] = compat->sig[7] | (((long)compat->sig[6]) << 32 ); + case 3: set->sig[2] = compat->sig[5] | (((long)compat->sig[4]) << 32 ); + case 2: set->sig[1] = compat->sig[3] | (((long)compat->sig[2]) << 32 ); + case 1: set->sig[0] = compat->sig[1] | (((long)compat->sig[0]) << 32 ); +#else + case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 ); + case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 ); + case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 ); + case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 ); +#endif + } +} + +asmlinkage long +compat_rt_sigtimedwait (compat_sigset_t __user *uthese, + struct compat_siginfo __user *uinfo, + struct compat_timespec __user *uts, compat_size_t sigsetsize) +{ + compat_sigset_t s32; + sigset_t s; + int sig; + struct timespec t; + siginfo_t info; + long ret, timeout = 0; + + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t))) + return -EFAULT; + sigset_from_compat(&s, &s32); + sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP)); + signotset(&s); + + if (uts) { + if (get_compat_timespec (&t, uts)) + return -EFAULT; + if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 + || t.tv_sec < 0) + return -EINVAL; + } + + spin_lock_irq(¤t->sighand->siglock); + sig = dequeue_signal(current, &s, &info); + if (!sig) { + timeout = MAX_SCHEDULE_TIMEOUT; + if (uts) + timeout = timespec_to_jiffies(&t) + +(t.tv_sec || t.tv_nsec); + if (timeout) { + current->real_blocked = current->blocked; + sigandsets(¤t->blocked, ¤t->blocked, &s); + + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + current->state = TASK_INTERRUPTIBLE; + timeout = schedule_timeout(timeout); + + spin_lock_irq(¤t->sighand->siglock); + sig = dequeue_signal(current, &s, &info); + current->blocked = current->real_blocked; + siginitset(¤t->real_blocked, 0); + recalc_sigpending(); + } + } + spin_unlock_irq(¤t->sighand->siglock); + + if (sig) { + ret = sig; + if (uinfo) { + if (copy_siginfo_to_user32(uinfo, &info)) + ret = -EFAULT; + } + }else { + ret = timeout?-EINTR:-EAGAIN; + } + return ret; + +} + #ifdef __ARCH_WANT_COMPAT_SYS_TIME /* compat_time_t is a 32 bit "long" and needs to get converted. */ |
