diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-12-25 14:31:38 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-02-03 15:09:19 -0500 |
commit | fe9c1db2cfc363cd30ecfe6480481b280abf8c0a (patch) | |
tree | 0382530cd58c72b56b9860d7bc5bab65a356d9a9 /kernel/signal.c | |
parent | 322a56cb1fcbe228eee5cdb8a9c6df9f797d998c (diff) | |
download | lwn-fe9c1db2cfc363cd30ecfe6480481b280abf8c0a.tar.gz lwn-fe9c1db2cfc363cd30ecfe6480481b280abf8c0a.zip |
generic compat_sys_rt_sigpending()
conditional on GENERIC_COMPAT_RT_SIGPENDING; by the end of that series
it will become the same thing as COMPAT and conditional will die out.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index bce1222b7315..3040c349b0e1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2654,28 +2654,19 @@ COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset, #endif #endif -long do_sigpending(void __user *set, unsigned long sigsetsize) +static int do_sigpending(void *set, unsigned long sigsetsize) { - long error = -EINVAL; - sigset_t pending; - if (sigsetsize > sizeof(sigset_t)) - goto out; + return -EINVAL; spin_lock_irq(¤t->sighand->siglock); - sigorsets(&pending, ¤t->pending.signal, + sigorsets(set, ¤t->pending.signal, ¤t->signal->shared_pending.signal); spin_unlock_irq(¤t->sighand->siglock); /* Outside the lock because only this thread touches it. */ - sigandsets(&pending, ¤t->blocked, &pending); - - error = -EFAULT; - if (!copy_to_user(set, &pending, sigsetsize)) - error = 0; - -out: - return error; + sigandsets(set, ¤t->blocked, set); + return 0; } /** @@ -2684,10 +2675,37 @@ out: * @set: stores pending signals * @sigsetsize: size of sigset_t type or larger */ -SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, set, size_t, sigsetsize) +SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize) +{ + sigset_t set; + int err = do_sigpending(&set, sigsetsize); + if (!err && copy_to_user(uset, &set, sigsetsize)) + err = -EFAULT; + return err; +} + +#ifdef CONFIG_COMPAT +#ifdef CONFIG_GENERIC_COMPAT_RT_SIGPENDING +COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset, + compat_size_t, sigsetsize) { - return do_sigpending(set, sigsetsize); +#ifdef __BIG_ENDIAN + sigset_t set; + int err = do_sigpending(&set, sigsetsize); + if (!err) { + compat_sigset_t set32; + sigset_to_compat(&set32, &set); + /* we can get here only if sigsetsize <= sizeof(set) */ + if (copy_to_user(uset, &set32, sigsetsize)) + err = -EFAULT; + } + return err; +#else + return sys_rt_sigpending((sigset_t __user *)uset, sigsetsize); +#endif } +#endif +#endif #ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER @@ -3216,7 +3234,7 @@ int __compat_save_altstack(compat_stack_t __user *uss, unsigned long sp) */ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set) { - return do_sigpending(set, sizeof(*set)); + return sys_rt_sigpending((sigset_t __user *)set, sizeof(old_sigset_t)); } #endif |