[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