Re: [RFC PATCH v6 00/26] Control-flow Enforcement: Shadow Stack

From: Andy Lutomirski
Date: Thu Nov 22 2018 - 11:53:25 EST


[cc some more libc folks]

I have a general question about this patch set:

If I'm writing a user program, and I write a signal handler, there are
two things I want to make sure I can still do:

1. I want to be able to unwind directly from the signal handler
without involving sigreturn() -- that is, I want to make sure that
siglongjmp() works. How does this work? Is INCSSP involved? How
exactly does the user program know how much to increment SSP by? (And
why on Earth does INCSSP only consider the low 8 bits of its argument?
That sounds like a mistake. Can Intel still fix that? On the other
hand, what happens if you INCSSP off the end of the shadow stack
entirely? I assume the next access will fault as long as there's an
appropriate guard page.)

2. I want to be able to modify the signal context from a signal
handler such that, when the signal handler returns, it will return to
a frame higher up on the call stack than where the signal started and
to a different RIP value. How can I do this? I guess I can modify
the shadow stack with WRSS if WR_SHSTK_EN=1, but how do I tell the
kernel to kindly skip the frames I want to skip when I do sigreturn()?

The reason I'm asking #2 is that I think it's time to resurrect my old
vDSO syscall cancellation helper series here:

https://lwn.net/Articles/679434/

and it's not at all clear to me that __vdso_abort_pending_syscall()
can work without kernel assistance when CET is enabled. I want to
make sure that it can be done, or I want to come up with some other
way to allow a signal handler to abort a syscall while CET is on. I
could probably change __vdso_abort_pending_syscall() to instead point
RIP to __kernel_vsyscall's epilogue so that we con't change the depth
of the call stack. But I could imagine that other user programs might
engage in similar shenanigans and want to have some way to unwind a
signal's return context without actually jumping there a la
siglongjmp().

Also, what is the intended setting of WR_SHSTK_EN with this patch set applied?

(I suppose we could just say that 32-bit processes should not use CET,
but that seems a bit sad.)