signal: Introduce copy_siginfo_from_user and use it's return value
authorEric W. Biederman <ebiederm@xmission.com>
Wed, 18 Apr 2018 22:30:19 +0000 (17:30 -0500)
committerEric W. Biederman <ebiederm@xmission.com>
Wed, 3 Oct 2018 14:47:15 +0000 (16:47 +0200)
In preparation for using a smaller version of siginfo in the kernel
introduce copy_siginfo_from_user and use it when siginfo is copied from
userspace.

Make the pattern for using copy_siginfo_from_user and
copy_siginfo_from_user32 to capture the return value and return that
value on error.

This is a necessary prerequisite for using a smaller siginfo
in the kernel than the kernel exports to userspace.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
include/linux/signal.h
kernel/ptrace.c
kernel/signal.c

index 3d4cd5d..de94c15 100644 (file)
@@ -22,6 +22,7 @@ static inline void clear_siginfo(struct siginfo *info)
 }
 
 int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);
+int copy_siginfo_from_user(struct siginfo *to, const struct siginfo __user *from);
 
 enum siginfo_layout {
        SIL_KILL,
index 45f77a1..a807ff5 100644 (file)
@@ -919,9 +919,8 @@ int ptrace_request(struct task_struct *child, long request,
                break;
 
        case PTRACE_SETSIGINFO:
-               if (copy_from_user(&siginfo, datavp, sizeof siginfo))
-                       ret = -EFAULT;
-               else
+               ret = copy_siginfo_from_user(&siginfo, datavp);
+               if (!ret)
                        ret = ptrace_setsiginfo(child, &siginfo);
                break;
 
@@ -1215,10 +1214,9 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
                break;
 
        case PTRACE_SETSIGINFO:
-               if (copy_siginfo_from_user32(
-                           &siginfo, (struct compat_siginfo __user *) datap))
-                       ret = -EFAULT;
-               else
+               ret = copy_siginfo_from_user32(
+                       &siginfo, (struct compat_siginfo __user *) datap);
+               if (!ret)
                        ret = ptrace_setsiginfo(child, &siginfo);
                break;
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
index debb485..c0e289e 100644 (file)
@@ -2896,6 +2896,13 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
        return 0;
 }
 
+int copy_siginfo_from_user(siginfo_t *to, const siginfo_t __user *from)
+{
+       if (copy_from_user(to, from, sizeof(struct siginfo)))
+               return -EFAULT;
+       return 0;
+}
+
 #ifdef CONFIG_COMPAT
 int copy_siginfo_to_user32(struct compat_siginfo __user *to,
                           const struct siginfo *from)
@@ -3323,8 +3330,9 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig,
                siginfo_t __user *, uinfo)
 {
        siginfo_t info;
-       if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
-               return -EFAULT;
+       int ret = copy_siginfo_from_user(&info, uinfo);
+       if (unlikely(ret))
+               return ret;
        return do_rt_sigqueueinfo(pid, sig, &info);
 }
 
@@ -3365,10 +3373,9 @@ SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig,
                siginfo_t __user *, uinfo)
 {
        siginfo_t info;
-
-       if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
-               return -EFAULT;
-
+       int ret = copy_siginfo_from_user(&info, uinfo);
+       if (unlikely(ret))
+               return ret;
        return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
 }
 
@@ -3380,9 +3387,9 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
                        struct compat_siginfo __user *, uinfo)
 {
        siginfo_t info;
-
-       if (copy_siginfo_from_user32(&info, uinfo))
-               return -EFAULT;
+       int ret = copy_siginfo_from_user32(&info, uinfo);
+       if (unlikely(ret))
+               return ret;
        return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
 }
 #endif