]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/unix/sysv/linux/x86_64/getcontext.S
x86-64/CET: Extend ucontext_t to save shadow stack
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / x86_64 / getcontext.S
index 33347bc02ea247068f73c849d5891320202eab96..84b986ca98ed310bee4f3afec18eacff305638d2 100644 (file)
@@ -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.  */