diff options
author | Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> | 2009-04-02 19:58:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-02 22:04:58 -0400 |
commit | 921cf9f63089c7442d44083477620132f4cea066 (patch) | |
tree | 2a79eb0f7328ba2f05759d1b2c1e141bcfe4aafc | |
parent | 7978b567d31555fc828b8f945c605ad29e117b22 (diff) |
signals: protect cinit from unblocked SIG_DFL signals
Drop early any SIG_DFL or SIG_IGN signals to container-init from within
the same container. But queue SIGSTOP and SIGKILL to the container-init
if they are from an ancestor container.
Blocked, fatal signals (i.e when SIG_DFL is to terminate) from within the
container can still terminate the container-init. That will be addressed
in the next patch.
Note: To be bisect-safe, SIGNAL_UNKILLABLE will be set for container-inits
in a follow-on patch. Until then, this patch is just a preparatory
step.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Daniel Lezcano <daniel.lezcano@free.fr>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | kernel/signal.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 7b6de962a1af..fb19aae2363b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -55,20 +55,21 @@ static int sig_handler_ignored(void __user *handler, int sig) | |||
55 | (handler == SIG_DFL && sig_kernel_ignore(sig)); | 55 | (handler == SIG_DFL && sig_kernel_ignore(sig)); |
56 | } | 56 | } |
57 | 57 | ||
58 | static int sig_task_ignored(struct task_struct *t, int sig) | 58 | static int sig_task_ignored(struct task_struct *t, int sig, |
59 | int from_ancestor_ns) | ||
59 | { | 60 | { |
60 | void __user *handler; | 61 | void __user *handler; |
61 | 62 | ||
62 | handler = sig_handler(t, sig); | 63 | handler = sig_handler(t, sig); |
63 | 64 | ||
64 | if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) && | 65 | if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) && |
65 | handler == SIG_DFL) | 66 | handler == SIG_DFL && !from_ancestor_ns) |
66 | return 1; | 67 | return 1; |
67 | 68 | ||
68 | return sig_handler_ignored(handler, sig); | 69 | return sig_handler_ignored(handler, sig); |
69 | } | 70 | } |
70 | 71 | ||
71 | static int sig_ignored(struct task_struct *t, int sig) | 72 | static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns) |
72 | { | 73 | { |
73 | /* | 74 | /* |
74 | * Blocked signals are never ignored, since the | 75 | * Blocked signals are never ignored, since the |
@@ -78,7 +79,7 @@ static int sig_ignored(struct task_struct *t, int sig) | |||
78 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) | 79 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) |
79 | return 0; | 80 | return 0; |
80 | 81 | ||
81 | if (!sig_task_ignored(t, sig)) | 82 | if (!sig_task_ignored(t, sig, from_ancestor_ns)) |
82 | return 0; | 83 | return 0; |
83 | 84 | ||
84 | /* | 85 | /* |
@@ -634,7 +635,7 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
634 | * Returns true if the signal should be actually delivered, otherwise | 635 | * Returns true if the signal should be actually delivered, otherwise |
635 | * it should be dropped. | 636 | * it should be dropped. |
636 | */ | 637 | */ |
637 | static int prepare_signal(int sig, struct task_struct *p) | 638 | static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) |
638 | { | 639 | { |
639 | struct signal_struct *signal = p->signal; | 640 | struct signal_struct *signal = p->signal; |
640 | struct task_struct *t; | 641 | struct task_struct *t; |
@@ -718,7 +719,7 @@ static int prepare_signal(int sig, struct task_struct *p) | |||
718 | } | 719 | } |
719 | } | 720 | } |
720 | 721 | ||
721 | return !sig_ignored(p, sig); | 722 | return !sig_ignored(p, sig, from_ancestor_ns); |
722 | } | 723 | } |
723 | 724 | ||
724 | /* | 725 | /* |
@@ -832,7 +833,8 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
832 | trace_sched_signal_send(sig, t); | 833 | trace_sched_signal_send(sig, t); |
833 | 834 | ||
834 | assert_spin_locked(&t->sighand->siglock); | 835 | assert_spin_locked(&t->sighand->siglock); |
835 | if (!prepare_signal(sig, t)) | 836 | |
837 | if (!prepare_signal(sig, t, from_ancestor_ns)) | ||
836 | return 0; | 838 | return 0; |
837 | 839 | ||
838 | pending = group ? &t->signal->shared_pending : &t->pending; | 840 | pending = group ? &t->signal->shared_pending : &t->pending; |
@@ -902,7 +904,15 @@ out_set: | |||
902 | static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | 904 | static int send_signal(int sig, struct siginfo *info, struct task_struct *t, |
903 | int group) | 905 | int group) |
904 | { | 906 | { |
905 | return __send_signal(sig, info, t, group, 0); | 907 | int from_ancestor_ns = 0; |
908 | |||
909 | #ifdef CONFIG_PID_NS | ||
910 | if (!is_si_special(info) && SI_FROMUSER(info) && | ||
911 | task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0) | ||
912 | from_ancestor_ns = 1; | ||
913 | #endif | ||
914 | |||
915 | return __send_signal(sig, info, t, group, from_ancestor_ns); | ||
906 | } | 916 | } |
907 | 917 | ||
908 | int print_fatal_signals; | 918 | int print_fatal_signals; |
@@ -1336,7 +1346,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group) | |||
1336 | goto ret; | 1346 | goto ret; |
1337 | 1347 | ||
1338 | ret = 1; /* the signal is ignored */ | 1348 | ret = 1; /* the signal is ignored */ |
1339 | if (!prepare_signal(sig, t)) | 1349 | if (!prepare_signal(sig, t, 0)) |
1340 | goto out; | 1350 | goto out; |
1341 | 1351 | ||
1342 | ret = 0; | 1352 | ret = 0; |