On Fri, Oct 29, 2021 at 10:09:04AM -0500, Eric W. Biederman wrote: > > As Andy pointed out that there are races between > force_sig_info_to_task and sigaction[1] when force_sig_info_task. As > Kees discovered[2] ptrace is also able to change these signals. > > In the case of seeccomp killing a process with a signal it is a > security violation to allow the signal to be caught or manipulated. > > Solve this problem by introducing a new flag SA_IMMUTABLE that > prevents sigaction and ptrace from modifying these forced signals. > This flag is carefully made kernel internal so that no new ABI is > introduced. > > Longer term I think this can be solved by guaranteeing short circuit > delivery of signals in this case. Unfortunately reliable and > guaranteed short circuit delivery of these signals is still a ways off > from being implemented, tested, and merged. So I have implemented a much > simpler alternative for now. > > [1] https://lkml.kernel.org/r/b5d52d25-7bde-4030-a7b1-7c6f8ab90660@xxxxxxxxxxxxxxxx > [2] https://lkml.kernel.org/r/202110281136.5CE65399A7@keescook > Cc: stable@xxxxxxxxxxxxxxx > Fixes: 307d522f5eb8 ("signal/seccomp: Refactor seccomp signal and coredump generation") > Signed-off-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> > --- FWIW I've tested this patch and I confirm that it fixes the failure that I reported with the seccomp_bpf selftest. Tested-by: Andrea Righi <andrea.righi@xxxxxxxxxxxxx> Thanks! -Andrea > > I have tested this patch and this changed works for me to fix the issue. > > I believe this closes all of the races that force_sig_info_to_task > has when sigdfl is specified. So this should be enough for anything > that needs a guaranteed that userspace can not race with the kernel > is handled. > > Can folks look this over and see if I missed something? > Thank you, > Eric > > > include/linux/signal_types.h | 3 +++ > include/uapi/asm-generic/signal-defs.h | 1 + > kernel/signal.c | 8 +++++++- > 3 files changed, 11 insertions(+), 1 deletion(-) > > diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h > index 34cb28b8f16c..927f7c0e5bff 100644 > --- a/include/linux/signal_types.h > +++ b/include/linux/signal_types.h > @@ -70,6 +70,9 @@ struct ksignal { > int sig; > }; > > +/* Used to kill the race between sigaction and forced signals */ > +#define SA_IMMUTABLE 0x008000000 > + > #ifndef __ARCH_UAPI_SA_FLAGS > #ifdef SA_RESTORER > #define __ARCH_UAPI_SA_FLAGS SA_RESTORER > diff --git a/include/uapi/asm-generic/signal-defs.h b/include/uapi/asm-generic/signal-defs.h > index fe929e7b77ca..7572f2f46ee8 100644 > --- a/include/uapi/asm-generic/signal-defs.h > +++ b/include/uapi/asm-generic/signal-defs.h > @@ -45,6 +45,7 @@ > #define SA_UNSUPPORTED 0x00000400 > #define SA_EXPOSE_TAGBITS 0x00000800 > /* 0x00010000 used on mips */ > +/* 0x00800000 used for internal SA_IMMUTABLE */ > /* 0x01000000 used on x86 */ > /* 0x02000000 used on x86 */ > /* > diff --git a/kernel/signal.c b/kernel/signal.c > index 6a5e1802b9a2..056a107e3cbc 100644 > --- a/kernel/signal.c > +++ b/kernel/signal.c > @@ -1336,6 +1336,7 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool > blocked = sigismember(&t->blocked, sig); > if (blocked || ignored || sigdfl) { > action->sa.sa_handler = SIG_DFL; > + action->sa.sa_flags |= SA_IMMUTABLE; > if (blocked) { > sigdelset(&t->blocked, sig); > recalc_sigpending_and_wake(t); > @@ -2760,7 +2761,8 @@ bool get_signal(struct ksignal *ksig) > if (!signr) > break; /* will return 0 */ > > - if (unlikely(current->ptrace) && signr != SIGKILL) { > + if (unlikely(current->ptrace) && (signr != SIGKILL) && > + !(sighand->action[signr -1].sa.sa_flags & SA_IMMUTABLE)) { > signr = ptrace_signal(signr, &ksig->info); > if (!signr) > continue; > @@ -4110,6 +4112,10 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) > k = &p->sighand->action[sig-1]; > > spin_lock_irq(&p->sighand->siglock); > + if (k->sa.sa_flags & SA_IMMUTABLE) { > + spin_unlock_irq(&p->sighand->siglock); > + return -EINVAL; > + } > if (oact) > *oact = *k; > > -- > 2.20.1