From: Kees Cook <keescook@chromium.org>
To: Jann Horn <jannh@google.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>,
"Robert Święcki" <robert@swiecki.net>,
stable@vger.kernel.org, "Andy Lutomirski" <luto@amacapital.net>,
"Will Drewry" <wad@chromium.org>,
linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org,
"Oleg Nesterov" <oleg@redhat.com>
Subject: Re: [PATCH 1/3] signal: HANDLER_EXIT should clear SIGNAL_UNKILLABLE
Date: Thu, 10 Feb 2022 13:09:13 -0800 [thread overview]
Message-ID: <202202101254.1174AB2B@keescook> (raw)
In-Reply-To: <CAG48ez3fG7S1dfE2-JAtyOZUK=0_iZ03scf+oD6gwVyD1Qp33g@mail.gmail.com>
On Thu, Feb 10, 2022 at 07:01:39PM +0100, Jann Horn wrote:
> On Thu, Feb 10, 2022 at 6:37 PM Kees Cook <keescook@chromium.org> wrote:
> > On Thu, Feb 10, 2022 at 05:18:39PM +0100, Jann Horn wrote:
> > > On Thu, Feb 10, 2022 at 3:53 AM Kees Cook <keescook@chromium.org> wrote:
> > > > Fatal SIGSYS signals were not being delivered to pid namespace init
> > > > processes. Make sure the SIGNAL_UNKILLABLE doesn't get set for these
> > > > cases.
> > > >
> > > > Reported-by: Robert Święcki <robert@swiecki.net>
> > > > Suggested-by: "Eric W. Biederman" <ebiederm@xmission.com>
> > > > Fixes: 00b06da29cf9 ("signal: Add SA_IMMUTABLE to ensure forced siganls do not get changed")
> > > > Cc: stable@vger.kernel.org
> > > > Signed-off-by: Kees Cook <keescook@chromium.org>
> > > > ---
> > > > kernel/signal.c | 5 +++--
> > > > 1 file changed, 3 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/kernel/signal.c b/kernel/signal.c
> > > > index 38602738866e..33e3ee4f3383 100644
> > > > --- a/kernel/signal.c
> > > > +++ b/kernel/signal.c
> > > > @@ -1342,9 +1342,10 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t,
> > > > }
> > > > /*
> > > > * Don't clear SIGNAL_UNKILLABLE for traced tasks, users won't expect
> > > > - * debugging to leave init killable.
> > > > + * debugging to leave init killable, unless it is intended to exit.
> > > > */
> > > > - if (action->sa.sa_handler == SIG_DFL && !t->ptrace)
> > > > + if (action->sa.sa_handler == SIG_DFL &&
> > > > + (!t->ptrace || (handler == HANDLER_EXIT)))
> > > > t->signal->flags &= ~SIGNAL_UNKILLABLE;
> > >
> > > You're changing the subclause:
> > >
> > > !t->ptrace
> > >
> > > to:
> > >
> > > (!t->ptrace || (handler == HANDLER_EXIT))
> > >
> > > which means that the change only affects cases where the process has a
> > > ptracer, right? That's not the scenario the commit message is talking
> > > about...
> >
> > Sorry, yes, I was not as accurate as I should have been in the commit
> > log. I have changed it to:
> >
> > Fatal SIGSYS signals (i.e. seccomp RET_KILL_* syscall filter actions)
> > were not being delivered to ptraced pid namespace init processes. Make
> > sure the SIGNAL_UNKILLABLE doesn't get set for these cases.
>
> So basically force_sig_info() is trying to figure out whether
> get_signal() will later on check for SIGNAL_UNKILLABLE (the SIG_DFL
> case), and if so, it clears the flag from the target's signal_struct
> that marks the process as unkillable?
>
> This used to be:
>
> if (action->sa.sa_handler == SIG_DFL)
> t->signal->flags &= ~SIGNAL_UNKILLABLE;
>
> Then someone noticed that in the ptrace case, the signal might not
> actually end up being consumed by the target process, and added the
> "&& !t->ptrace" clause in commit
> eb61b5911bdc923875cde99eb25203a0e2b06d43.
>
> And now Robert Swiecki noticed that that still didn't accurately model
> what'll happen in get_signal().
>
> This seems hacky to me, and also racy: What if, while you're going
> through a SECCOMP_RET_KILL_PROCESS in an unkillable process, some
> other thread e.g. concurrently changes the disposition of SIGSYS from
> a custom handler to SIG_DFL?
Do you mean after force_sig_info_to_task() has finished but before
get_signal()? SA_IMMUTABLE will block changes to the action.
If you mean before force_sig_info_to_task(), I don't see how that's
possible since it's under lock:
if (blocked || ignored || (handler != HANDLER_CURRENT)) {
action->sa.sa_handler = SIG_DFL;
if (handler == HANDLER_EXIT)
action->sa.sa_flags |= SA_IMMUTABLE;
...
if (action->sa.sa_handler == SIG_DFL &&
(!t->ptrace || (handler == HANDLER_EXIT)))
t->signal->flags &= ~SIGNAL_UNKILLABLE;
Given handler = HANDLER_EXIT, it'll always be SIG_DFL.
> Instead of trying to figure out whether the signal would have been
> fatal without SIGNAL_UNKILLABLE, I think it would be better to find a
> way to tell the signal-handling code that SIGNAL_UNKILLABLE should be
> bypassed for this specific signal, or something along those lines...
> but of course that's also kind of messy because the signal-sending
> code might fall back to just using the pending signal mask on
> allocation failure IIRC?
My original patch aimed that way:
diff --git a/kernel/signal.c b/kernel/signal.c
index 9b04631acde8..c124a09de6de 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2787,7 +2787,8 @@ bool get_signal(struct ksignal *ksig)
* case, the signal cannot be dropped.
*/
if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&
- !sig_kernel_only(signr))
+ !sig_kernel_only(signr) &&
+ !(ka->sa.sa_flags & SA_IMMUTABLE))
continue;
if (sig_kernel_stop(signr)) {
But I don't think there's a race, and Eric's suggestion seemed
better in the sense that the state change is entirely contained by
force_sig_info_to_task().
-Kees
--
Kees Cook
next prev parent reply other threads:[~2022-02-10 21:09 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-10 2:53 [PATCH 0/3] signal: HANDLER_EXIT should clear SIGNAL_UNKILLABLE Kees Cook
2022-02-10 2:53 ` [PATCH 1/3] " Kees Cook
2022-02-10 16:18 ` Jann Horn
2022-02-10 17:37 ` Kees Cook
2022-02-10 18:01 ` Jann Horn
2022-02-10 18:12 ` Eric W. Biederman
2022-02-10 21:09 ` Kees Cook [this message]
2022-02-11 20:15 ` Jann Horn
2022-02-10 18:16 ` Eric W. Biederman
2022-02-10 2:53 ` [PATCH 2/3] seccomp: Invalidate seccomp mode to catch death failures Kees Cook
2022-02-10 2:53 ` [PATCH 3/3] samples/seccomp: Adjust sample to also provide kill option Kees Cook
2022-02-10 18:17 ` [PATCH 0/3] signal: HANDLER_EXIT should clear SIGNAL_UNKILLABLE Eric W. Biederman
2022-02-10 18:41 ` Kees Cook
2022-02-10 18:58 ` Eric W. Biederman
2022-02-10 20:43 ` Kees Cook
2022-02-10 22:48 ` Eric W. Biederman
2022-02-11 1:26 ` Kees Cook
2022-02-11 1:47 ` Eric W. Biederman
2022-02-11 2:53 ` Kees Cook
2022-02-11 12:54 ` Robert Święcki
2022-02-11 17:46 ` Eric W. Biederman
2022-02-11 18:57 ` Robert Święcki
2022-02-11 20:01 ` Kees Cook
2022-02-11 19:58 ` Kees Cook
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=202202101254.1174AB2B@keescook \
--to=keescook@chromium.org \
--cc=ebiederm@xmission.com \
--cc=jannh@google.com \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=oleg@redhat.com \
--cc=robert@swiecki.net \
--cc=stable@vger.kernel.org \
--cc=wad@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.