signalfd: lift sigmask copyin and size checks to callers of do_signalfd4()
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 27 May 2018 12:35:50 +0000 (08:35 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 15 Jun 2018 04:23:50 +0000 (00:23 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/signalfd.c

index d2187a813376cab46f63c11bb1e1eb572bf07775..46e9de097507ae95f00bc427bc48fa400039956a 100644 (file)
@@ -256,10 +256,8 @@ static const struct file_operations signalfd_fops = {
        .llseek         = noop_llseek,
 };
 
-static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
-                       int flags)
+static int do_signalfd4(int ufd, sigset_t *mask, int flags)
 {
-       sigset_t sigmask;
        struct signalfd_ctx *ctx;
 
        /* Check the SFD_* constants for consistency.  */
@@ -269,18 +267,15 @@ static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
        if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK))
                return -EINVAL;
 
-       if (sizemask != sizeof(sigset_t) ||
-           copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
-               return -EINVAL;
-       sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-       signotset(&sigmask);
+       sigdelsetmask(mask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+       signotset(mask);
 
        if (ufd == -1) {
                ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
                if (!ctx)
                        return -ENOMEM;
 
-               ctx->sigmask = sigmask;
+               ctx->sigmask = *mask;
 
                /*
                 * When we call this, the initialization must be complete, since
@@ -300,7 +295,7 @@ static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
                        return -EINVAL;
                }
                spin_lock_irq(&current->sighand->siglock);
-               ctx->sigmask = sigmask;
+               ctx->sigmask = *mask;
                spin_unlock_irq(&current->sighand->siglock);
 
                wake_up(&current->sighand->signalfd_wqh);
@@ -313,46 +308,51 @@ static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
 SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask,
                size_t, sizemask, int, flags)
 {
-       return do_signalfd4(ufd, user_mask, sizemask, flags);
+       sigset_t mask;
+
+       if (sizemask != sizeof(sigset_t) ||
+           copy_from_user(&mask, user_mask, sizeof(mask)))
+               return -EINVAL;
+       return do_signalfd4(ufd, &mask, flags);
 }
 
 SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask,
                size_t, sizemask)
 {
-       return do_signalfd4(ufd, user_mask, sizemask, 0);
+       sigset_t mask;
+
+       if (sizemask != sizeof(sigset_t) ||
+           copy_from_user(&mask, user_mask, sizeof(mask)))
+               return -EINVAL;
+       return do_signalfd4(ufd, &mask, 0);
 }
 
 #ifdef CONFIG_COMPAT
 static long do_compat_signalfd4(int ufd,
-                       const compat_sigset_t __user *sigmask,
+                       const compat_sigset_t __user *user_mask,
                        compat_size_t sigsetsize, int flags)
 {
-       sigset_t tmp;
-       sigset_t __user *ksigmask;
+       sigset_t mask;
 
        if (sigsetsize != sizeof(compat_sigset_t))
                return -EINVAL;
-       if (get_compat_sigset(&tmp, sigmask))
-               return -EFAULT;
-       ksigmask = compat_alloc_user_space(sizeof(sigset_t));
-       if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
+       if (get_compat_sigset(&mask, user_mask))
                return -EFAULT;
-
-       return do_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags);
+       return do_signalfd4(ufd, &mask, flags);
 }
 
 COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd,
-                    const compat_sigset_t __user *, sigmask,
+                    const compat_sigset_t __user *, user_mask,
                     compat_size_t, sigsetsize,
                     int, flags)
 {
-       return do_compat_signalfd4(ufd, sigmask, sigsetsize, flags);
+       return do_compat_signalfd4(ufd, user_mask, sigsetsize, flags);
 }
 
 COMPAT_SYSCALL_DEFINE3(signalfd, int, ufd,
-                    const compat_sigset_t __user *,sigmask,
+                    const compat_sigset_t __user *, user_mask,
                     compat_size_t, sigsetsize)
 {
-       return do_compat_signalfd4(ufd, sigmask, sigsetsize, 0);
+       return do_compat_signalfd4(ufd, user_mask, sigsetsize, 0);
 }
 #endif