Thread (9 messages) 9 messages, 4 authors, 2016-05-14

Re: [PATCH 1/4] signals/sigaltstack: If SS_AUTODISARM, bypass on_sig_stack

flat view

From: Andy Lutomirski <luto@amacapital.net>
Date: 2016-05-14 16:36:05
Also in: lkml

On May 14, 2016 4:18 AM, "Stas Sergeev" [off-list ref] wrote:
14.05.2016 07:18, Andy Lutomirski пишет:
quoted
On May 8, 2016 7:05 PM, "Stas Sergeev" [off-list ref] wrote:
quoted
09.05.2016 04:32, Andy Lutomirski пишет:
quoted
On May 7, 2016 7:38 AM, "Stas Sergeev" [off-list ref] wrote:
quoted
03.05.2016 20:31, Andy Lutomirski пишет:
quoted
If a signal stack is set up with SS_AUTODISARM, then the kernel
inherently avoids incorrectly resetting the signal stack if signals
recurse: the signal stack will be reset on the first signal
delivery.  This means that we don't need check the stack pointer
when delivering signals if SS_AUTODISARM is set.

This will make segmented x86 programs more robust: currently there's
a hole that could be triggered if ESP/RSP appears to point to the
signal stack but actually doesn't due to a nonzero SS base.

Signed-off-by: Stas Sergeev <redacted>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Aleksa Sarai <redacted>
Cc: Amanieu d'Antras <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <redacted>
Cc: Denys Vlasenko <redacted>
Cc: Eric W. Biederman <redacted>
Cc: Frederic Weisbecker <redacted>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Heinrich Schuchardt <redacted>
Cc: Jason Low <redacted>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Konstantin Khlebnikov <redacted>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Moore <redacted>
Cc: Pavel Emelyanov <redacted>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: Sasha Levin <redacted>
Cc: Shuah Khan <redacted>
Cc: Tejun Heo <tj@kernel.org>
Cc: Thomas Gleixner <redacted>
Cc: Vladimir Davydov <redacted>
Cc: linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
    include/linux/sched.h | 12 ++++++++++++
    1 file changed, 12 insertions(+)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2950c5cd3005..8f03a93348b9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2576,6 +2576,18 @@ static inline int kill_cad_pid(int sig, int priv)
     */
    static inline int on_sig_stack(unsigned long sp)
    {
+       /*
+        * If the signal stack is AUTODISARM then, by construction, we
+        * can't be on the signal stack unless user code deliberately set
+        * SS_AUTODISARM when we were already on the it.
"on the it" -> "on it".

Anyway, I am a bit puzzled with this patch.
You say "unless user code deliberately set

SS_AUTODISARM when we were already on the it"
so what happens in case it actually does?
Stack corruption.  Don't do that.
Only after your change, I have to admit. :)

quoted
quoted
Without your patch: if user sets up the same sas - no stack switch.
if user sets up different sas - stack switch on nested signal.

With your patch: stack switch in any case, so if user
set up same sas - stack corruption by nested signal.

Or am I missing the intention?
The intention is to make everything completely explicit.  With
SS_AUTODISARM, the kernel knows directly whether you're on the signal
stack, and there should be no need to look at sp.  If you set
SS_AUTODISARM and get a signal, the signal stack gets disarmed.  If
you take a nested signal, it's delivered normally.  When you return
all the way out, the signal stack is re-armed.

For DOSEMU, this means that no 16-bit register state can possibly
cause a signal to be delivered wrong, because the register state when
a signal is raised won't affect delivery, which seems like a good
thing to me.
Yes, but doesn't affect dosemu1 which doesn't use SS_AUTODISARM.
So IMHO the SS check should still be added, even if not for dosemu2.

quoted
If this behavior would be problematic for you, can you explain why?
Only theoretically: if someone sets SS_AUTODISARM inside a
sighandler. Since this doesn't give EPERM, I wouldn't deliberately
make it a broken scenario (esp if it wasn't before the particular change).
Ideally it would give EPERM, but we can't, so doesn't matter much.
I just wanted to warn about the possible regression.
I suppose we could return an error if you are on the sigstack when
setting SS_AUTODISARM, although I was hoping to avoid yet more special
cases.
Hmm.
How about extending the generic check then?
Currently it is roughly:
if (on_sig_stack(sp)) return -EPERM;

and we could do:
if (on_sig_stack(sp) || on_new_sas(new_sas, sp)) return -EPERM;

Looks like it will close the potential hole opened by your commit
without introducing the special case for SS_AUTODISARM.
What do you think?
It's still a wee bit ugly.  Also, doesn't that change existing
behavior for the existing non-AUTODISARM case?  Also, we'd have to
make sure that sigreturn doesn't trigger this check.

My inclination would be leave it alone.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help