diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/x86_64/getcontext.S')
-rw-r--r-- | sysdeps/unix/sysv/linux/x86_64/getcontext.S | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/x86_64/getcontext.S b/sysdeps/unix/sysv/linux/x86_64/getcontext.S index 33347bc02e..84b986ca98 100644 --- a/sysdeps/unix/sysv/linux/x86_64/getcontext.S +++ b/sysdeps/unix/sysv/linux/x86_64/getcontext.S @@ -18,6 +18,7 @@ <http://www.gnu.org/licenses/>. */ #include <sysdep.h> +#include <asm/prctl.h> #include "ucontext_i.h" @@ -53,6 +54,55 @@ ENTRY(__getcontext) leaq 8(%rsp), %rcx /* Exclude the return address. */ movq %rcx, oRSP(%rdi) +#if SHSTK_ENABLED + /* Check if shadow stack is enabled. */ + testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET + jz L(no_shstk) + + /* Save RDI in RDX which won't be clobbered by syscall. */ + movq %rdi, %rdx + + xorl %eax, %eax + cmpq %fs:SSP_BASE_OFFSET, %rax + jnz L(shadow_stack_bound_recorded) + + /* Get the base address and size of the default shadow stack + which must be the current shadow stack since nothing has + been recorded yet. */ + sub $24, %RSP_LP + mov %RSP_LP, %RSI_LP + movl $ARCH_CET_STATUS, %edi + movl $__NR_arch_prctl, %eax + syscall + testq %rax, %rax + jz L(continue_no_err) + + /* This should never happen. */ + hlt + +L(continue_no_err): + /* Record the base of the current shadow stack. */ + movq 8(%rsp), %rax + movq %rax, %fs:SSP_BASE_OFFSET + add $24, %RSP_LP + + /* Restore RDI. */ + movq %rdx, %rdi + +L(shadow_stack_bound_recorded): + /* Get the current shadow stack pointer. */ + rdsspq %rax + /* NB: Save the caller's shadow stack so that we can jump back + to the caller directly. */ + addq $8, %rax + movq %rax, oSSP(%rdx) + + /* Save the current shadow stack base in ucontext. */ + movq %fs:SSP_BASE_OFFSET, %rax + movq %rax, (oSSP + 8)(%rdi) + +L(no_shstk): +#endif /* We have separate floating-point register content memory on the stack. We use the __fpregs_mem block in the context. Set the links up correctly. */ |