[PATCH] x86-64/cet: Check the restore token in longjmp

Noah Goldstein goldstein.w.n@gmail.com
Mon Jan 1 18:02:53 GMT 2024


On Mon, Jan 1, 2024 at 6:03 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> setcontext and swapcontext put a restore token on the old shadow stack
> which is used to restore the target shadow stack when switching user
> contexts.  When longjmp from a user context, the target shadow stack
> can be different from the current shadow stack and INCSSP can't be
> used to restore the shadow stack pointer to the target shadow stack.
>
> Update longjmp to search for a restore token.  If found, use the token
> to restore the shadow stack pointer before using INCSSP to pop the
> shadow stack.  Stop the token search and use INCSSP if the shadow stack
> entry value is the same as the current shadow stack pointer.
>
> It is a user error if there is a shadow stack switch without leaving a
> restore token on the old shadow stack.
> ---
>  .../unix/sysv/linux/x86_64/____longjmp_chk.S  | 30 ++++++++++++++++++-
>  sysdeps/x86_64/__longjmp.S                    | 30 ++++++++++++++++++-
>  2 files changed, 58 insertions(+), 2 deletions(-)
>
> diff --git a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
> index 1b735bbbb2..855c934218 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
> +++ b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
> @@ -121,9 +121,37 @@ ENTRY(____longjmp_chk)
>  # endif
>         /* Check and adjust the Shadow-Stack-Pointer.  */
>         rdsspq  %rax
> +       /* Save the current ssp.  */
> +       movq    %rax, %r10
> +       movq    SHADOW_STACK_POINTER_OFFSET(%rdi), %rcx
>         /* And compare it with the saved ssp value.  */
> -       subq    SHADOW_STACK_POINTER_OFFSET(%rdi), %rax
> +       subq    %rcx, %rax
>         je      L(skip_ssp)
> +
> +L(find_restore_token_loop):
> +       /* Look for a restore token.  */
> +       movq    -8(%rcx), %rbx
> +       andq    $-8, %rbx
> +       cmpq    %rcx, %rbx
> +       /* Find the restore token.  */
> +       je      L(restore_shadow_stack)
> +
> +       /* Try the next slot.  */
> +       subq    $8, %rcx
> +       /* Stop if the current ssp is found.  */
> +       cmpq    %rcx, %r10
> +       je      L(no_shadow_stack_token)
> +       jmp     L(find_restore_token_loop)
> +
> +L(restore_shadow_stack):
> +       /* Restore the target shadow stack.  */
> +       rstorssp -8(%rcx)
> +       /* Save the restore token on the old shadow stack.  */
> +       saveprevssp
> +       rdsspq  %rax
> +       subq    SHADOW_STACK_POINTER_OFFSET(%rdi), %rax
> +
> +L(no_shadow_stack_token):
>         /* Count the number of frames to adjust and adjust it
>            with incssp instruction.  The instruction can adjust
>            the ssp by [0..255] value only thus use a loop if
> diff --git a/sysdeps/x86_64/__longjmp.S b/sysdeps/x86_64/__longjmp.S
> index 9ac075e0a8..4f449115e6 100644
> --- a/sysdeps/x86_64/__longjmp.S
> +++ b/sysdeps/x86_64/__longjmp.S
> @@ -63,9 +63,37 @@ ENTRY(__longjmp)
>         /* Check and adjust the Shadow-Stack-Pointer.  */
>         /* Get the current ssp.  */
>         rdsspq %rax
> +       /* Save the current ssp.  */
> +       movq %rax, %r10
>         /* And compare it with the saved ssp value.  */
> -       subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax
> +       movq SHADOW_STACK_POINTER_OFFSET(%rdi), %rcx
> +       subq %rcx, %rax
cmpq?
>         je L(skip_ssp)
> +
> +L(find_restore_token_loop):
> +       /* Look for a restore token.  */
> +       movq -8(%rcx), %rbx
> +       andq $-8, %rbx
> +       cmpq %rcx, %rbx
> +       /* Find the restore token.  */
> +       je L(restore_shadow_stack)
> +
> +       /* Try the next slot.  */
> +       subq $8, %rcx
> +       /* Stop if the current ssp is found.  */
> +       cmpq %rcx, %r10
> +       je L(no_shadow_stack_token)
> +       jmp L(find_restore_token_loop)
jne  L(find_restore_token_loop)
jmp L(no_shadow_stack_token)
to save a branch in the loop itself.

> +
> +L(restore_shadow_stack):
> +       /* Restore the target shadow stack.  */
> +       rstorssp -8(%rcx)

Does this not need to be the aligned address?

> +       /* Save the restore token on the old shadow stack.  */
> +       saveprevssp
> +       rdsspq %rax
> +       subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax

maybe cache `SHADOW_STACK_POINTER_OFFSET(%rdi)` in some
free register above?
> +
> +L(no_shadow_stack_token):
Looks like duplicate between __longjmp.S and __longjmp_chk.S.
Can we either 1) make these functions or 2) define them as a macro
to be included by both?
>         /* Count the number of frames to adjust and adjust it
>            with incssp instruction.  The instruction can adjust
>            the ssp by [0..255] value only thus use a loop if
> --
> 2.43.0
>


More information about the Libc-alpha mailing list