summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-03-19 17:03:41 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-07 08:53:36 -0700
commit59a49b056b6f7a0207cbde94c7163ed365be82e1 (patch)
tree97b97ff3d0810938ce5dedbf940447718148b180
parentf799aa1565fc056504ba7473a09e8f0dee3a20b7 (diff)
exit_signal: fix the "parent has changed security domain" logic
commit b6e238dceed36891cc633167afe7151f1f3d83c5 upstream. exit_notify() changes ->exit_signal if the parent already did exec. This doesn't really work, we are not going to send the signal now if there is another live thread or the exiting task is traced. The parent can exec before the last dies or the tracer detaches. Move this check into do_notify_parent() which actually sends the signal. The user-visible change is that we do not change ->exit_signal, and thus the exiting task is still "clone children" for do_wait()->eligible_child(__WCLONE). Hopefully this is fine, the current logic is racy anyway. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/exit.c14
-rw-r--r--kernel/signal.c9
2 files changed, 9 insertions, 14 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 7348c28f0df7..46c8b14ebf07 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -818,20 +818,6 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
if (group_dead)
kill_orphaned_pgrp(tsk->group_leader, NULL);
- /* Let father know we died
- *
- * Thread signals are configurable, but you aren't going to use
- * that to send signals to arbitrary processes.
- * That stops right now.
- *
- * If the parent exec id doesn't match the exec id we saved
- * when we started then we know the parent has changed security
- * domain.
- */
- if (thread_group_leader(tsk) && tsk->exit_signal != SIGCHLD &&
- tsk->parent_exec_id != tsk->real_parent->self_exec_id)
- tsk->exit_signal = SIGCHLD;
-
if (unlikely(tsk->ptrace)) {
int sig = thread_group_leader(tsk) &&
thread_group_empty(tsk) &&
diff --git a/kernel/signal.c b/kernel/signal.c
index c73c4284160e..b09cf3b8a4dd 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1642,6 +1642,15 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
BUG_ON(!tsk->ptrace &&
(tsk->group_leader != tsk || !thread_group_empty(tsk)));
+ if (sig != SIGCHLD) {
+ /*
+ * This is only possible if parent == real_parent.
+ * Check if it has changed security domain.
+ */
+ if (tsk->parent_exec_id != tsk->parent->self_exec_id)
+ sig = SIGCHLD;
+ }
+
info.si_signo = sig;
info.si_errno = 0;
/*