aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2019-02-06 19:39:40 -0500
committerEric W. Biederman <ebiederm@xmission.com>2019-02-07 09:59:50 -0500
commit35634ffa1751b6efd8cf75010b509dcb0263e29b (patch)
tree1782d141daf1fb0de74117125ab0965edd139241 /kernel
parenta692933a87691681e880feb708081681ff32400a (diff)
signal: Always notice exiting tasks
Recently syzkaller was able to create unkillablle processes by creating a timer that is delivered as a thread local signal on SIGHUP, and receiving SIGHUP SA_NODEFERER. Ultimately causing a loop failing to deliver SIGHUP but always trying. Upon examination it turns out part of the problem is actually most of the solution. Since 2.5 signal delivery has found all fatal signals, marked the signal group for death, and queued SIGKILL in every threads thread queue relying on signal->group_exit_code to preserve the information of which was the actual fatal signal. The conversion of all fatal signals to SIGKILL results in the synchronous signal heuristic in next_signal kicking in and preferring SIGHUP to SIGKILL. Which is especially problematic as all fatal signals have already been transformed into SIGKILL. Instead of dequeueing signals and depending upon SIGKILL to be the first signal dequeued, first test if the signal group has already been marked for death. This guarantees that nothing in the signal queue can prevent a process that needs to exit from exiting. Cc: stable@vger.kernel.org Tested-by: Dmitry Vyukov <dvyukov@google.com> Reported-by: Dmitry Vyukov <dvyukov@google.com> Ref: ebf5ebe31d2c ("[PATCH] signal-fixes-2.5.59-A4") History Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/signal.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 9ca8e5278c8e..5424cb0006bc 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2393,6 +2393,11 @@ relock:
2393 goto relock; 2393 goto relock;
2394 } 2394 }
2395 2395
2396 /* Has this task already been marked for death? */
2397 ksig->info.si_signo = signr = SIGKILL;
2398 if (signal_group_exit(signal))
2399 goto fatal;
2400
2396 for (;;) { 2401 for (;;) {
2397 struct k_sigaction *ka; 2402 struct k_sigaction *ka;
2398 2403
@@ -2488,6 +2493,7 @@ relock:
2488 continue; 2493 continue;
2489 } 2494 }
2490 2495
2496 fatal:
2491 spin_unlock_irq(&sighand->siglock); 2497 spin_unlock_irq(&sighand->siglock);
2492 2498
2493 /* 2499 /*