Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6
[sfrench/cifs-2.6.git] / kernel / signal.c
index 1c8814481a117d5df731465b5a56bbf4738c48c1..d8034737db4cb86f8adca044560a3765ac65dba5 100644 (file)
@@ -55,10 +55,22 @@ static int sig_handler_ignored(void __user *handler, int sig)
                (handler == SIG_DFL && sig_kernel_ignore(sig));
 }
 
-static int sig_ignored(struct task_struct *t, int sig)
+static int sig_task_ignored(struct task_struct *t, int sig,
+               int from_ancestor_ns)
 {
        void __user *handler;
 
+       handler = sig_handler(t, sig);
+
+       if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
+                       handler == SIG_DFL && !from_ancestor_ns)
+               return 1;
+
+       return sig_handler_ignored(handler, sig);
+}
+
+static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
+{
        /*
         * Blocked signals are never ignored, since the
         * signal handler may change by the time it is
@@ -67,14 +79,13 @@ static int sig_ignored(struct task_struct *t, int sig)
        if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
                return 0;
 
-       handler = sig_handler(t, sig);
-       if (!sig_handler_ignored(handler, sig))
+       if (!sig_task_ignored(t, sig, from_ancestor_ns))
                return 0;
 
        /*
         * Tracers may want to know about even ignored signals.
         */
-       return !tracehook_consider_ignored_signal(t, sig, handler);
+       return !tracehook_consider_ignored_signal(t, sig);
 }
 
 /*
@@ -318,7 +329,7 @@ int unhandled_signal(struct task_struct *tsk, int sig)
                return 1;
        if (handler != SIG_IGN && handler != SIG_DFL)
                return 0;
-       return !tracehook_consider_fatal_signal(tsk, sig, handler);
+       return !tracehook_consider_fatal_signal(tsk, sig);
 }
 
 
@@ -624,7 +635,7 @@ static int check_kill_permission(int sig, struct siginfo *info,
  * Returns true if the signal should be actually delivered, otherwise
  * it should be dropped.
  */
-static int prepare_signal(int sig, struct task_struct *p)
+static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
 {
        struct signal_struct *signal = p->signal;
        struct task_struct *t;
@@ -708,7 +719,7 @@ static int prepare_signal(int sig, struct task_struct *p)
                }
        }
 
-       return !sig_ignored(p, sig);
+       return !sig_ignored(p, sig, from_ancestor_ns);
 }
 
 /*
@@ -777,7 +788,7 @@ static void complete_signal(int sig, struct task_struct *p, int group)
            !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
            !sigismember(&t->real_blocked, sig) &&
            (sig == SIGKILL ||
-            !tracehook_consider_fatal_signal(t, sig, SIG_DFL))) {
+            !tracehook_consider_fatal_signal(t, sig))) {
                /*
                 * This signal will be fatal to the whole group.
                 */
@@ -813,8 +824,8 @@ static inline int legacy_queue(struct sigpending *signals, int sig)
        return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
 }
 
-static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
-                       int group)
+static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
+                       int group, int from_ancestor_ns)
 {
        struct sigpending *pending;
        struct sigqueue *q;
@@ -822,7 +833,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
        trace_sched_signal_send(sig, t);
 
        assert_spin_locked(&t->sighand->siglock);
-       if (!prepare_signal(sig, t))
+
+       if (!prepare_signal(sig, t, from_ancestor_ns))
                return 0;
 
        pending = group ? &t->signal->shared_pending : &t->pending;
@@ -871,6 +883,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
                        break;
                default:
                        copy_siginfo(&q->info, info);
+                       if (from_ancestor_ns)
+                               q->info.si_pid = 0;
                        break;
                }
        } else if (!is_si_special(info)) {
@@ -889,6 +903,20 @@ out_set:
        return 0;
 }
 
+static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+                       int group)
+{
+       int from_ancestor_ns = 0;
+
+#ifdef CONFIG_PID_NS
+       if (!is_si_special(info) && SI_FROMUSER(info) &&
+                       task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0)
+               from_ancestor_ns = 1;
+#endif
+
+       return __send_signal(sig, info, t, group, from_ancestor_ns);
+}
+
 int print_fatal_signals;
 
 static void print_fatal_signal(struct pt_regs *regs, int signr)
@@ -1133,7 +1161,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
        if (sig && p->sighand) {
                unsigned long flags;
                spin_lock_irqsave(&p->sighand->siglock, flags);
-               ret = __group_send_sig_info(sig, info, p);
+               ret = __send_signal(sig, info, p, 1, 0);
                spin_unlock_irqrestore(&p->sighand->siglock, flags);
        }
 out_unlock:
@@ -1320,7 +1348,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
                goto ret;
 
        ret = 1; /* the signal is ignored */
-       if (!prepare_signal(sig, t))
+       if (!prepare_signal(sig, t, 0))
                goto out;
 
        ret = 0;
@@ -1844,9 +1872,16 @@ relock:
 
                /*
                 * Global init gets no signals it doesn't want.
+                * Container-init gets no signals it doesn't want from same
+                * container.
+                *
+                * Note that if global/container-init sees a sig_kernel_only()
+                * signal here, the signal must have been generated internally
+                * or must have come from an ancestor namespace. In either
+                * case, the signal cannot be dropped.
                 */
                if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&
-                   !signal_group_exit(signal))
+                               !sig_kernel_only(signr))
                        continue;
 
                if (sig_kernel_stop(signr)) {