signals: fix sigqueue_free() vs __exit_signal() race
Changes
2 files changed · +8 −2
| File | Status | Add | Del | Content |
|---|---|---|---|---|
| kernel/exit.c | modified | +6 | −1 | View file |
| kernel/signal.c | modified | +2 | −1 | View file |
kernel/exit.c
View filediff --git a/kernel/exit.c b/kernel/exit.c
index 1510f78..8f6185e 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -126,6 +126,12 @@ static void __exit_signal(struct task_struct *tsk)
__unhash_process(tsk);
+ /*
+ * Do this under ->siglock, we can race with another thread
+ * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals.
+ */
+ flush_sigqueue(&tsk->pending);
+
tsk->signal = NULL;
tsk->sighand = NULL;
spin_unlock(&sighand->siglock);
@@ -133,7 +139,6 @@ static void __exit_signal(struct task_struct *tsk)
__cleanup_sighand(sighand);
clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
- flush_sigqueue(&tsk->pending);
if (sig) {
flush_sigqueue(&sig->shared_pending);
taskstats_tgid_free(sig);
kernel/signal.c
View filediff --git a/kernel/signal.c b/kernel/signal.c
index 72bb4f5..12ffea7 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1242,7 +1242,8 @@ void sigqueue_free(struct sigqueue *q)
/*
* If the signal is still pending remove it from the
* pending queue. We must hold ->siglock while testing
- * q->list to serialize with collect_signal().
+ * q->list to serialize with collect_signal() or with
+ * __exit_signal()->flush_sigqueue().
*/
spin_lock_irqsave(lock, flags);
if (!list_empty(&q->list))