summaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux/x86_64/getcontext.S
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/x86_64/getcontext.S')
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/getcontext.S50
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. */