[PATCH 13/14] signal: Dequeue fatal signals
From: Eric W. Biederman
Date: Fri Jul 03 2026 - 17:44:30 EST
Fatal signals are detected early and historically have not been
dequeued. This barely matters as the process exits immediately.
Not dequeuing the signal is visible to userspace inspecting the dying
process through proc and will be to coredumps once we start using
short circuit delivery for them.
Update the short circuit delivery for fatal signals to always place
the fatal signal on the shared signal queue.
To keep things simple always populate siginfo in dequeue_exit_signal
and always pass the dequeueed siginfo to trace_signal_deliver.
Signed-off-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx>
---
include/linux/sched/signal.h | 1 +
kernel/signal.c | 43 +++++++++++++++++++++++++++++-------
2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 4ff1da6b841e..17a5930cf98a 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -262,6 +262,7 @@ struct signal_struct {
#define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */
#define SIGNAL_STOP_CONTINUED 0x00000002 /* SIGCONT since WCONTINUED reap */
#define SIGNAL_GROUP_EXIT 0x00000004 /* group exit in progress */
+#define SIGNAL_EXIT_DEQUEUE 0x00000008 /* Dequeue the exit signal */
/*
* Pending notifications to parent.
*/
diff --git a/kernel/signal.c b/kernel/signal.c
index 674d4b6d0b8a..5bd07a90c689 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -708,6 +708,36 @@ int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type)
}
EXPORT_SYMBOL_GPL(dequeue_signal);
+static int dequeue_exit_signal(
+ struct task_struct *tsk, int exit_code, kernel_siginfo_t *info)
+{
+ struct signal_struct *signal = tsk->signal;
+
+ /* The default siginfo to return */
+ clear_siginfo(info);
+ info->si_signo = SIGKILL;
+ info->si_code = SI_KERNEL;
+
+ if (signal->flags & SIGNAL_EXIT_DEQUEUE) {
+ int sig = exit_code;
+ signal->flags &= ~SIGNAL_EXIT_DEQUEUE;
+
+ struct sigqueue *q =
+ list_last_entry_or_null(&signal->shared_pending.list,
+ struct sigqueue, list);
+ if (q && (q->info.si_signo == sig)) {
+ list_del_init(&q->list);
+ copy_siginfo(info, &q->info);
+ __sigqueue_free(q);
+ } else {
+ info->si_signo = sig;
+ }
+ sigdelset(&signal->shared_pending.signal, sig);
+ }
+
+ return info->si_signo;
+}
+
static int dequeue_synchronous_signal(kernel_siginfo_t *info)
{
struct task_struct *tsk = current;
@@ -1071,7 +1101,8 @@ static void enqueue_signal(struct task_struct *t, enum pid_type type,
* running and doing things after a slower
* thread has the fatal signal pending.
*/
- signal->flags = SIGNAL_GROUP_EXIT;
+ pending = &signal->shared_pending;
+ signal->flags = SIGNAL_GROUP_EXIT | SIGNAL_EXIT_DEQUEUE;
signal->group_exit_code = sig;
signal->group_stop_count = 0;
__for_each_thread(signal, thread) {
@@ -2917,15 +2948,11 @@ bool get_signal(struct ksignal *ksig)
signal->group_exec_task) {
if (signal->flags & SIGNAL_GROUP_EXIT)
exit_code = signal->group_exit_code;
- signr = SIGKILL;
sigdelset(¤t->pending.signal, SIGKILL);
- trace_signal_deliver(SIGKILL, SEND_SIG_NOINFO,
- &sighand->action[SIGKILL-1]);
+ signr = dequeue_exit_signal(current, exit_code, &ksig->info);
+ trace_signal_deliver(signr, &ksig->info,
+ &sighand->action[signr-1]);
recalc_sigpending();
- /*
- * implies do_group_exit() or return to PF_USER_WORKER,
- * no need to initialize ksig->info/etc.
- */
goto fatal;
}
--
2.41.0