Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[safe/jmp/linux-2.6] / kernel / signal.c
index d2dd9cf..809a228 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
 #include <linux/nsproxy.h>
-#include <trace/sched.h>
+#include <trace/events/sched.h>
 
 #include <asm/param.h>
 #include <asm/uaccess.h>
@@ -41,8 +41,6 @@
 
 static struct kmem_cache *sigqueue_cachep;
 
-DEFINE_TRACE(sched_signal_send);
-
 static void __user *sig_handler(struct task_struct *t, int sig)
 {
        return t->sighand->action[sig - 1].sa.sa_handler;
@@ -2283,24 +2281,17 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
        return kill_something_info(sig, &info, pid);
 }
 
-static int do_tkill(pid_t tgid, pid_t pid, int sig)
+static int
+do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
 {
-       int error;
-       struct siginfo info;
        struct task_struct *p;
        unsigned long flags;
-
-       error = -ESRCH;
-       info.si_signo = sig;
-       info.si_errno = 0;
-       info.si_code = SI_TKILL;
-       info.si_pid = task_tgid_vnr(current);
-       info.si_uid = current_uid();
+       int error = -ESRCH;
 
        rcu_read_lock();
        p = find_task_by_vpid(pid);
        if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) {
-               error = check_kill_permission(sig, &info, p);
+               error = check_kill_permission(sig, info, p);
                /*
                 * The null signal is a permissions and process existence
                 * probe.  No signal is actually delivered.
@@ -2310,7 +2301,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
                 * signal is private anyway.
                 */
                if (!error && sig && lock_task_sighand(p, &flags)) {
-                       error = specific_send_sig_info(sig, &info, p);
+                       error = specific_send_sig_info(sig, info, p);
                        unlock_task_sighand(p, &flags);
                }
        }
@@ -2319,6 +2310,19 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
        return error;
 }
 
+static int do_tkill(pid_t tgid, pid_t pid, int sig)
+{
+       struct siginfo info;
+
+       info.si_signo = sig;
+       info.si_errno = 0;
+       info.si_code = SI_TKILL;
+       info.si_pid = task_tgid_vnr(current);
+       info.si_uid = current_uid();
+
+       return do_send_specific(tgid, pid, sig, &info);
+}
+
 /**
  *  sys_tgkill - send signal to one specific thread
  *  @tgid: the thread group ID of the thread
@@ -2368,6 +2372,32 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig,
        return kill_proc_info(sig, &info, pid);
 }
 
+long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
+{
+       /* This is only valid for single tasks */
+       if (pid <= 0 || tgid <= 0)
+               return -EINVAL;
+
+       /* Not even root can pretend to send signals from the kernel.
+          Nor can they impersonate a kill(), which adds source info.  */
+       if (info->si_code >= 0)
+               return -EPERM;
+       info->si_signo = sig;
+
+       return do_send_specific(tgid, pid, sig, info);
+}
+
+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;
+
+       return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
+}
+
 int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 {
        struct task_struct *t = current;