[PATCH v2 1/3] signal: change force_sig_info_to_task() to call __send_signal_locked()
From: Oleg Nesterov
Date: Fri Jun 19 2026 - 09:27:31 EST
force_sig_info_to_task() calls send_signal_locked() which does two
things on top of __send_signal_locked():
1. The namespace translation of si_pid/si_uid. However, forced signals
carry fault info (si_addr, si_call_addr, si_syscall), not pid/uid.
The force_sig*() API should never be used to send signals with
meaningful si_pid/si_uid, the forced signals are always "from kernel".
There are few users of force_sig(SIGKILL), and in this case
send_signal_locked() -> has_si_pid_and_uid() returns true.
However, __send_signal_locked() simply ignores kernel_siginfo if
sig == SIGKILL.
(and in fact force_sig(SIGKILL) makes little sense, they should
use send_sig(SIGKILL, p, 1) instead)
2. The "force" computation. However, for the forced signals, the
unconditional force == true works just fine.
If the target is ptraced, the "force" arg has no effect unless
sig == SIGKILL.
Otherwise, this check in sig_task_ignored()
if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
handler == SIG_DFL && !(force && sig_kernel_only(sig)))
return true;
has no effect, force_sig_info_to_task() clears SIGNAL_UNKILLABLE
if handler == SIG_DFL.
The only behavioral difference is another check in sig_task_ignored:
if (unlikely((t->flags & PF_KTHREAD) &&
(handler == SIG_KTHREAD_KERNEL) && !force))
So with this patch a kthread that called allow_kernel_signal()
for a fault signal would now receive the forced signal instead
of silently ignoring it.
And this is arguably more correct, even if I don't think that
the force_sig*() API should be used in this case.
Signed-off-by: Oleg Nesterov <oleg@xxxxxxxxxx>
---
kernel/signal.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/signal.c b/kernel/signal.c
index 9c2b32c4d755..68af503ed43c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1315,7 +1315,7 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t,
if (action->sa.sa_handler == SIG_DFL &&
(!t->ptrace || (handler == HANDLER_EXIT)))
t->signal->flags &= ~SIGNAL_UNKILLABLE;
- ret = send_signal_locked(sig, info, t, PIDTYPE_PID);
+ ret = __send_signal_locked(sig, info, t, PIDTYPE_PID, true);
/* This can happen if the signal was already pending and blocked */
if (!task_sigpending(t))
signal_wake_up(t, 0);
--
2.52.0