generic compat_sys_rt_sigpending()
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 25 Dec 2012 19:31:38 +0000 (14:31 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 3 Feb 2013 20:09:19 +0000 (15:09 -0500)
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>
arch/Kconfig
include/linux/compat.h
include/linux/signal.h
kernel/signal.c

index 374a68adbf1f9644ef6d290431eb52b70e1a3914..18c0383dcc4245a9c0d6c0b3398125f662e4c366 100644 (file)
@@ -362,6 +362,9 @@ config GENERIC_SIGALTSTACK
 config GENERIC_COMPAT_RT_SIGPROCMASK
        bool
 
+config GENERIC_COMPAT_RT_SIGPENDING
+       bool
+
 #
 # ABI hall of shame
 #
index 9d3c2a98d537c94dabf06c95d83881f51577d2a1..75548a43a1c5431e3db9f122e82f6df29e4f40dd 100644 (file)
@@ -598,6 +598,10 @@ asmlinkage long compat_sys_rt_sigprocmask(int how, compat_sigset_t __user *set,
                                          compat_sigset_t __user *oset,
                                          compat_size_t sigsetsize);
 #endif
+#ifdef CONFIG_GENERIC_COMPAT_RT_SIGPENDING
+asmlinkage long compat_sys_rt_sigpending(compat_sigset_t __user *uset,
+                                        compat_size_t sigsetsize);
+#endif
 asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info);
 asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
                                 unsigned long arg);
index 0a89ffc4846669c7bfa5f6289e8563decb84c520..786bd99fde65eaf52c3012668caa992ab97ff7cf 100644 (file)
@@ -243,7 +243,6 @@ extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig,
                                 siginfo_t *info);
-extern long do_sigpending(void __user *, unsigned long);
 extern int do_sigtimedwait(const sigset_t *, siginfo_t *,
                                const struct timespec *);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
index bce1222b73159ec5d7877e7394849f5ee8a5d002..3040c349b0e1168b50662727b28bf3883f40df39 100644 (file)
@@ -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(&current->sighand->siglock);
-       sigorsets(&pending, &current->pending.signal,
+       sigorsets(set, &current->pending.signal,
                  &current->signal->shared_pending.signal);
        spin_unlock_irq(&current->sighand->siglock);
 
        /* Outside the lock because only this thread touches it.  */
-       sigandsets(&pending, &current->blocked, &pending);
-
-       error = -EFAULT;
-       if (!copy_to_user(set, &pending, sigsetsize))
-               error = 0;
-
-out:
-       return error;
+       sigandsets(set, &current->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