generic compat_sys_rt_sigqueueinfo()
[firefly-linux-kernel-4.4.55.git] / kernel / signal.c
index 3040c349b0e1168b50662727b28bf3883f40df39..6cd3023cc66b0dd32149e3468c2d0cfedd9e39f9 100644 (file)
@@ -2983,6 +2983,22 @@ SYSCALL_DEFINE2(tkill, pid_t, pid, int, sig)
        return do_tkill(0, pid, sig);
 }
 
+static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info)
+{
+       /* Not even root can pretend to send signals from the kernel.
+        * Nor can they impersonate a kill()/tgkill(), which adds source info.
+        */
+       if (info->si_code >= 0 || info->si_code == SI_TKILL) {
+               /* We used to allow any < 0 si_code */
+               WARN_ON_ONCE(info->si_code < 0);
+               return -EPERM;
+       }
+       info->si_signo = sig;
+
+       /* POSIX.1b doesn't mention process groups.  */
+       return kill_proc_info(sig, info, pid);
+}
+
 /**
  *  sys_rt_sigqueueinfo - send signal information to a signal
  *  @pid: the PID of the thread
@@ -2993,23 +3009,26 @@ 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;
+       return do_rt_sigqueueinfo(pid, sig, &info);
+}
 
-       /* Not even root can pretend to send signals from the kernel.
-        * Nor can they impersonate a kill()/tgkill(), which adds source info.
-        */
-       if (info.si_code >= 0 || info.si_code == SI_TKILL) {
-               /* We used to allow any < 0 si_code */
-               WARN_ON_ONCE(info.si_code < 0);
-               return -EPERM;
-       }
-       info.si_signo = sig;
-
-       /* POSIX.1b doesn't mention process groups.  */
-       return kill_proc_info(sig, &info, pid);
+#ifdef CONFIG_COMPAT
+#ifdef CONFIG_GENERIC_COMPAT_RT_SIGQUEUEINFO
+COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
+                       compat_pid_t, pid,
+                       int, sig,
+                       struct compat_siginfo __user *, uinfo)
+{
+       siginfo_t info;
+       int ret = copy_siginfo_from_user32(&info, uinfo);
+       if (unlikely(ret))
+               return ret;
+       return do_rt_sigqueueinfo(pid, sig, &info);
 }
+#endif
+#endif
 
 long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
 {