Thread (54 messages) 54 messages, 6 authors, 2023-07-12

Re: [PATCH v9 23/42] Documentation/x86: Add CET shadow stack description

From: szabolcs.nagy@arm.com <hidden>
Date: 2023-06-22 08:29:22
Also in: linux-arch, linux-doc, linux-mm, lkml

The 06/21/2023 22:22, Edgecombe, Rick P wrote:
On Wed, 2023-06-21 at 11:54 -0700, Rick Edgecombe wrote:
quoted
quoted
quoted
quoted
quoted
quoted
quoted
there is no magic, longjmp should be implemented as:

        target_ssp = read from jmpbuf;
        current_ssp = read ssp;
        for (p = target_ssp; p != current_ssp; p--) {
                if (*p == restore-token) {
                        // target_ssp is on a different
shstk.
                        switch_shstk_to(p);
                        break;
                }
        }
        for (; p != target_ssp; p++)
                // ssp is now on the same shstk as
target.
                inc_ssp();

this is what setcontext is doing and longjmp can do the
same:
for programs that always longjmp within the same shstk
the
first
loop is just p = current_ssp, but it also works when
longjmp
target is on a different shstk assuming nothing is
running
on
that shstk, which is only possible if there is a restore
token
on top.

this implies if the kernel switches shstk on signal entry
it has
to add a restore-token on the switched away shstk.
Wait a second, the claim is that the kernel should add a restore token
on the current shadow stack before handling a signal, to allow to
unwind from an alt shadow stack, right? But in this series there is not
an alt shadow stack, so signal will be handled on the current shadow
stack. If the user stays on the current shadow stack, the existing
simple INCSSP based solution will work.
yes.
If the user swapcontext()'s away while handling a signal (which *is*
currently supported) they will leave their own restore token on the old
stack. Hypothetically glibc could unwind back through a series of
ucontext stacks by pivoting, if it kept some metadata somewhere about
where to restore to. So there are actually already enough tokens to
make it back in this case, glibc just doesn't do this.
swapcontext is currently *not* supported: for it to work you have to
be able to jump *back* into the signal handler, which does not work if
the swapcontext target is on the original thread stack (instead of
say a makecontext stack).

jumping back can only be supported if alt stack can be paired with
an alt shadow stack.

unwinding across a series of signal interrupts should work even
with discontinous shstk. libgcc does not implement this which is
a problem i think.
But how does the proposed token placed by the kernel on the original
stack help this problem? The longjmp() would have to be able to find
the location of the restore tokens somehow, which would not necessarily
be near the setjmp() point. The signal token could even be on a
different shadow stack.
i posted the exact longjmp code and it takes care of this case.

setjmp does not need to do anything special.

the invariant is that an shstk is either capped by a restore token
or in use by some executing task. this is guaranteed architecturally
(when shstk is switched with an instruction) and should be guaranteed
by the kernel too (when shstk is switched by the kernel).
I'm also not sure leaving a token on signal doesn't weaken the security
it it's own way as well. Any thread could then swap to that token.
Where as the shadow stack signal frame ssp pointer can only be used
from the shadow stack the signal was handled on.
as far as i'm concerned it is a valid programming model to switch
to a stack that is currently not in use and we should always allow
that. (signal handled on an alt stack may not return)
So I think, in addition to blocking the shadow stack overflow use case
in the future, leaving a token behind on signal will not really help
longjmp(). (or at least I'm not following)
the restore token must only be added if shstk is switched
(currently it is not switched so don't add it, however if
we agree on this then the unwinder can be fixed accordingly.)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help