Home Home > GIT Browse > stable
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2019-02-15 10:23:48 +0100
committerJiri Slaby <jslaby@suse.cz>2019-02-15 10:23:57 +0100
commitf97e1227aad47c0e4f67d7f35be6ec698e1f209a (patch)
treeef8901b1f7288770054783c3b2b607ccd6543c47
parent9b529399e266e702f4ef83056d93614179cc93d4 (diff)
signal: Better detection of synchronous signals (bnc#1012628).
-rw-r--r--patches.kernel.org/4.20.9-012-signal-Better-detection-of-synchronous-signals.patch121
-rw-r--r--series.conf1
2 files changed, 122 insertions, 0 deletions
diff --git a/patches.kernel.org/4.20.9-012-signal-Better-detection-of-synchronous-signals.patch b/patches.kernel.org/4.20.9-012-signal-Better-detection-of-synchronous-signals.patch
new file mode 100644
index 0000000000..a88b83f3d7
--- /dev/null
+++ b/patches.kernel.org/4.20.9-012-signal-Better-detection-of-synchronous-signals.patch
@@ -0,0 +1,121 @@
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 6 Feb 2019 17:51:47 -0600
+Subject: [PATCH] signal: Better detection of synchronous signals
+References: bnc#1012628
+Patch-mainline: 4.20.9
+Git-commit: 7146db3317c67b517258cb5e1b08af387da0618b
+
+commit 7146db3317c67b517258cb5e1b08af387da0618b upstream.
+
+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.
+
+When the stack overflows delivery of SIGHUP fails and force_sigsegv is
+called. Unfortunately because SIGSEGV is numerically higher than
+SIGHUP next_signal tries again to deliver a SIGHUP.
+
+From a quality of implementation standpoint attempting to deliver the
+timer SIGHUP signal is wrong. We should attempt to deliver the
+synchronous SIGSEGV signal we just forced.
+
+We can make that happening in a fairly straight forward manner by
+instead of just looking at the signal number we also look at the
+si_code. In particular for exceptions (aka synchronous signals) the
+si_code is always greater than 0.
+
+That still has the potential to pick up a number of asynchronous
+signals as in a few cases the same si_codes that are used
+for synchronous signals are also used for asynchronous signals,
+and SI_KERNEL is also included in the list of possible si_codes.
+
+Still the heuristic is much better and timer signals are definitely
+excluded. Which is enough to prevent all known ways for someone
+sending a process signals fast enough to cause unexpected and
+arguably incorrect behavior.
+
+Cc: stable@vger.kernel.org
+Fixes: a27341cd5fcb ("Prioritize synchronous signals over 'normal' signals")
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+---
+ kernel/signal.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 51 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 091302d45169..cf4cf68c3ea8 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -688,6 +688,48 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *in
+ }
+ EXPORT_SYMBOL_GPL(dequeue_signal);
+
++static int dequeue_synchronous_signal(kernel_siginfo_t *info)
++{
++ struct task_struct *tsk = current;
++ struct sigpending *pending = &tsk->pending;
++ struct sigqueue *q, *sync = NULL;
++
++ /*
++ * Might a synchronous signal be in the queue?
++ */
++ if (!((pending->signal.sig[0] & ~tsk->blocked.sig[0]) & SYNCHRONOUS_MASK))
++ return 0;
++
++ /*
++ * Return the first synchronous signal in the queue.
++ */
++ list_for_each_entry(q, &pending->list, list) {
++ /* Synchronous signals have a postive si_code */
++ if ((q->info.si_code > SI_USER) &&
++ (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) {
++ sync = q;
++ goto next;
++ }
++ }
++ return 0;
++next:
++ /*
++ * Check if there is another siginfo for the same signal.
++ */
++ list_for_each_entry_continue(q, &pending->list, list) {
++ if (q->info.si_signo == sync->info.si_signo)
++ goto still_pending;
++ }
++
++ sigdelset(&pending->signal, sync->info.si_signo);
++ recalc_sigpending();
++still_pending:
++ list_del_init(&sync->list);
++ copy_siginfo(info, &sync->info);
++ __sigqueue_free(sync);
++ return info->si_signo;
++}
++
+ /*
+ * Tell a process that it has a new active signal..
+ *
+@@ -2411,7 +2453,15 @@ bool get_signal(struct ksignal *ksig)
+ goto relock;
+ }
+
+- signr = dequeue_signal(current, &current->blocked, &ksig->info);
++ /*
++ * Signals generated by the execution of an instruction
++ * need to be delivered before any other pending signals
++ * so that the instruction pointer in the signal stack
++ * frame points to the faulting instruction.
++ */
++ signr = dequeue_synchronous_signal(&ksig->info);
++ if (!signr)
++ signr = dequeue_signal(current, &current->blocked, &ksig->info);
+
+ if (!signr)
+ break; /* will return 0 */
+--
+2.20.1
+
diff --git a/series.conf b/series.conf
index 941df89ad1..a953cad21d 100644
--- a/series.conf
+++ b/series.conf
@@ -1094,6 +1094,7 @@
patches.kernel.org/4.20.9-009-iio-ti-ads8688-Update-buffer-allocation-for-ti.patch
patches.kernel.org/4.20.9-010-signal-Always-attempt-to-allocate-siginfo-for-.patch
patches.kernel.org/4.20.9-011-signal-Always-notice-exiting-tasks.patch
+ patches.kernel.org/4.20.9-012-signal-Better-detection-of-synchronous-signals.patch
########################################################
# Build fixes that apply to the vanilla kernel too.