summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-09-21 15:44:58 +0200
committerChristian Brauner <brauner@kernel.org>2026-09-22 15:33:16 +0200
commitcabc249e6560bee7bdfee9fbcb7ce4e951dcfd41 (patch)
tree73a2f271ce3f032aac2f2223059bc71a1aadb66a
parent62badefdbab34c0dc3c4ec13c09787dc4d50b4bb (diff)
downloadlinux-next-cabc249e6560bee7bdfee9fbcb7ce4e951dcfd41.tar.gz
linux-next-cabc249e6560bee7bdfee9fbcb7ce4e951dcfd41.zip
ptrace: refuse to change the signal mask of a user worker
A user worker is created with every signal other than SIGKILL and SIGSTOP blocked. It never runs user code and that mask is what keeps get_signal() from dequeuing anything else for it. complete_signal() never picks a thread that blocks the signal, tkill() queues on the worker but nothing dequeues it. ptrace_signal() requeues an injected signal that the tracee blocks. PTRACE_SETSIGMASK is the only way to change that mask from the outside. A tracer that clears it makes the worker eligible for every signal. Whatever the worker then dequeues it can only act on by leaving. Refuse PTRACE_SETSIGMASK for a user worker with -EPERM, the way ptrace_attach() refuses a kernel thread. A worker is guaranteed to only ever dequeue SIGKILL or SIGSTOP and an injected signal stays pending on it, which is what already happens when the mask isn't touched. Taking the request and quietly leaving the mask alone was the other option, the way set_current_blocked() keeps SIGKILL and SIGSTOP unblocked whatever userspace asks for. But then a tracer gets success back with nothing changed and no way to tell that apart from a mask that took effect. Fixes: e8b33b8cfafc ("Revert "kernel: treat PF_IO_WORKER like PF_KTHREAD for ptrace/signals"") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260921-work-coredump-fixes-v3-9-8e4adb1619e6@kernel.org Acked-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
-rw-r--r--kernel/ptrace.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d041645d9d17..4e9822a87aab 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -1227,6 +1227,12 @@ int ptrace_request(struct task_struct *child, long request,
case PTRACE_SETSIGMASK: {
sigset_t new_set;
+ /* A user worker only ever takes SIGKILL and SIGSTOP. */
+ if (child->flags & PF_USER_WORKER) {
+ ret = -EPERM;
+ break;
+ }
+
if (addr != sizeof(sigset_t)) {
ret = -EINVAL;
break;