summaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-07-14 05:59:29 -0700
committerH.J. Lu <hjl.tools@gmail.com>2018-07-14 05:59:53 -0700
commitfaaee1f07ed25b2779bfd935ffb29f431b80d6d3 (patch)
tree3c85f88e2312c67e0f0e54be10b0bec833c7541f /sysdeps
parentebff9c5cfae62e84dbd0456d564bd882818dc15f (diff)
x86: Support shadow stack pointer in setjmp/longjmp
Save and restore shadow stack pointer in setjmp and longjmp to support shadow stack in Intel CET. Use feature_1 in tcbhead_t to check if shadow stack is enabled before saving and restoring shadow stack pointer. Reviewed-by: Carlos O'Donell <carlos@redhat.com> * sysdeps/i386/__longjmp.S: Include <jmp_buf-ssp.h>. (__longjmp): Restore shadow stack pointer if shadow stack is enabled, SHADOW_STACK_POINTER_OFFSET is defined and __longjmp isn't defined for __longjmp_cancel. * sysdeps/i386/bsd-_setjmp.S: Include <jmp_buf-ssp.h>. (_setjmp): Save shadow stack pointer if shadow stack is enabled and SHADOW_STACK_POINTER_OFFSET is defined. * sysdeps/i386/bsd-setjmp.S: Include <jmp_buf-ssp.h>. (setjmp): Save shadow stack pointer if shadow stack is enabled and SHADOW_STACK_POINTER_OFFSET is defined. * sysdeps/i386/setjmp.S: Include <jmp_buf-ssp.h>. (__sigsetjmp): Save shadow stack pointer if shadow stack is enabled and SHADOW_STACK_POINTER_OFFSET is defined. * sysdeps/unix/sysv/linux/i386/____longjmp_chk.S: Include <jmp_buf-ssp.h>. (____longjmp_chk): Restore shadow stack pointer if shadow stack is enabled and SHADOW_STACK_POINTER_OFFSET is defined. * sysdeps/unix/sysv/linux/x86/Makefile (gen-as-const-headers): Remove jmp_buf-ssp.sym. * sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S: Include <jmp_buf-ssp.h>. (____longjmp_chk): Restore shadow stack pointer if shadow stack is enabled and SHADOW_STACK_POINTER_OFFSET is defined. * sysdeps/x86/Makefile (gen-as-const-headers): Add jmp_buf-ssp.sym. * sysdeps/x86/jmp_buf-ssp.sym: New dummy file. * sysdeps/x86_64/__longjmp.S: Include <jmp_buf-ssp.h>. (__longjmp): Restore shadow stack pointer if shadow stack is enabled, SHADOW_STACK_POINTER_OFFSET is defined and __longjmp isn't defined for __longjmp_cancel. * sysdeps/x86_64/setjmp.S: Include <jmp_buf-ssp.h>. (__sigsetjmp): Save shadow stack pointer if shadow stack is enabled and SHADOW_STACK_POINTER_OFFSET is defined.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/i386/__longjmp.S73
-rw-r--r--sysdeps/i386/bsd-_setjmp.S21
-rw-r--r--sysdeps/i386/bsd-setjmp.S21
-rw-r--r--sysdeps/i386/setjmp.S21
-rw-r--r--sysdeps/unix/sysv/linux/i386/____longjmp_chk.S37
-rw-r--r--sysdeps/unix/sysv/linux/x86/Makefile1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S38
-rw-r--r--sysdeps/x86/Makefile1
-rw-r--r--sysdeps/x86/jmp_buf-ssp.sym1
-rw-r--r--sysdeps/x86_64/__longjmp.S44
-rw-r--r--sysdeps/x86_64/setjmp.S21
11 files changed, 278 insertions, 1 deletions
diff --git a/sysdeps/i386/__longjmp.S b/sysdeps/i386/__longjmp.S
index b38333bead..6e98ed538d 100644
--- a/sysdeps/i386/__longjmp.S
+++ b/sysdeps/i386/__longjmp.S
@@ -18,14 +18,55 @@
#include <sysdep.h>
#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
#include <asm-syntax.h>
#include <stap-probe.h>
+/* Don't restore shadow stack register if
+ 1. Shadow stack isn't enabled. Or
+ 2. __longjmp is defined for __longjmp_cancel.
+ */
+#if !SHSTK_ENABLED || defined __longjmp
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
+
.text
ENTRY (__longjmp)
#ifdef PTR_DEMANGLE
movl 4(%esp), %eax /* User's jmp_buf in %eax. */
+# ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %edx, %edx
+# endif
+ /* Check and adjust the Shadow-Stack-Pointer. */
+ rdsspd %edx
+ /* And compare it with the saved ssp value. */
+ subl SHADOW_STACK_POINTER_OFFSET(%eax), %edx
+ je L(skip_ssp)
+ /* 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
+ the number of frames is bigger than 255. */
+ negl %edx
+ shrl $2, %edx
+ /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are
+ restoring Shadow-Stack-Pointer of setjmp's caller, we
+ need to unwind shadow stack by one more frame. */
+ addl $1, %edx
+ movl $255, %ebx
+L(loop):
+ cmpl %ebx, %edx
+ cmovb %edx, %ebx
+ incsspd %ebx
+ subl %ebx, %edx
+ ja L(loop)
+L(skip_ssp):
+# endif
/* Save the return address now. */
movl (JB_PC*4)(%eax), %edx
/* Get the stack pointer. */
@@ -56,6 +97,38 @@ ENTRY (__longjmp)
#else
movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */
movl 8(%esp), %eax /* Second argument is return value. */
+# ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# endif
+ /* Check and adjust the Shadow-Stack-Pointer. */
+ xorl %edx, %edx
+ /* Get the current ssp. */
+ rdsspd %edx
+ /* And compare it with the saved ssp value. */
+ subl SHADOW_STACK_POINTER_OFFSET(%ecx), %edx
+ je L(skip_ssp)
+ /* 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
+ the number of frames is bigger than 255. */
+ negl %edx
+ shrl $2, %edx
+ /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are
+ restoring Shadow-Stack-Pointer of setjmp's caller, we
+ need to unwind shadow stack by one more frame. */
+ addl $1, %edx
+ movl $255, %ebx
+L(loop):
+ cmpl %ebx, %edx
+ cmovb %edx, %ebx
+ incsspd %ebx
+ subl %ebx, %edx
+ ja L(loop)
+L(skip_ssp):
+# endif
/* Save the return address now. */
movl (JB_PC*4)(%ecx), %edx
LIBC_PROBE (longjmp, 3, 4@%ecx, -4@%eax, 4@%edx)
diff --git a/sysdeps/i386/bsd-_setjmp.S b/sysdeps/i386/bsd-_setjmp.S
index a626cc6d22..db47df0ba1 100644
--- a/sysdeps/i386/bsd-_setjmp.S
+++ b/sysdeps/i386/bsd-_setjmp.S
@@ -22,12 +22,18 @@
#include <sysdep.h>
#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
#include <stap-probe.h>
#define PARMS 4 /* no space for saved regs */
#define JMPBUF PARMS
#define SIGMSK JMPBUF+4
+/* Don't save shadow stack register if shadow stack isn't enabled. */
+#if !SHSTK_ENABLED
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
+
ENTRY (_setjmp)
xorl %eax, %eax
@@ -51,6 +57,21 @@ ENTRY (_setjmp)
movl %ebp, (JB_BP*4)(%edx) /* Save caller's frame pointer. */
movl %eax, JB_SIZE(%edx) /* No signal mask set. */
+#ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %ecx, %ecx
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ rdsspd %ecx
+ movl %ecx, SHADOW_STACK_POINTER_OFFSET(%edx)
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+L(skip_ssp):
+# endif
+#endif
ret
END (_setjmp)
libc_hidden_def (_setjmp)
diff --git a/sysdeps/i386/bsd-setjmp.S b/sysdeps/i386/bsd-setjmp.S
index 2da8b73c49..1290d0d82b 100644
--- a/sysdeps/i386/bsd-setjmp.S
+++ b/sysdeps/i386/bsd-setjmp.S
@@ -22,12 +22,18 @@
#include <sysdep.h>
#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
#include <stap-probe.h>
#define PARMS 4 /* no space for saved regs */
#define JMPBUF PARMS
#define SIGMSK JMPBUF+4
+/* Don't save shadow stack register if shadow stack isn't enabled. */
+#if !SHSTK_ENABLED
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
+
ENTRY (setjmp)
/* Note that we have to use a non-exported symbol in the next
jump since otherwise gas will emit it as a jump through the
@@ -51,6 +57,21 @@ ENTRY (setjmp)
#endif
movl %ecx, (JB_PC*4)(%eax)
movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */
+#ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %ecx, %ecx
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ rdsspd %ecx
+ movl %ecx, SHADOW_STACK_POINTER_OFFSET(%eax)
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+L(skip_ssp):
+# endif
+#endif
/* Call __sigjmp_save. */
pushl $1
diff --git a/sysdeps/i386/setjmp.S b/sysdeps/i386/setjmp.S
index 6a08701717..889337b8ae 100644
--- a/sysdeps/i386/setjmp.S
+++ b/sysdeps/i386/setjmp.S
@@ -18,6 +18,7 @@
#include <sysdep.h>
#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
#include <asm-syntax.h>
#include <stap-probe.h>
@@ -25,6 +26,11 @@
#define JMPBUF PARMS
#define SIGMSK JMPBUF+4
+/* Don't save shadow stack register if shadow stack isn't enabled. */
+#if !SHSTK_ENABLED
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
+
ENTRY (__sigsetjmp)
movl JMPBUF(%esp), %eax
@@ -46,6 +52,21 @@ ENTRY (__sigsetjmp)
movl %ecx, (JB_PC*4)(%eax)
movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */
+#ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %ecx, %ecx
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ rdsspd %ecx
+ movl %ecx, SHADOW_STACK_POINTER_OFFSET(%eax)
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+L(skip_ssp):
+# endif
+#endif
#if IS_IN (rtld)
/* In ld.so we never save the signal mask. */
xorl %eax, %eax
diff --git a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
index 3452433112..a7640d9892 100644
--- a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
+++ b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
@@ -17,9 +17,14 @@
#include <sysdep.h>
#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
#include <asm-syntax.h>
#include <stap-probe.h>
+/* Don't restore shadow stack register if shadow stack isn't enabled. */
+#if !SHSTK_ENABLED
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
.section .rodata.str1.1,"aMS",@progbits,1
.type longjmp_msg,@object
@@ -46,6 +51,38 @@ longjmp_msg:
ENTRY (____longjmp_chk)
movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */
+#ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %edx, %edx
+# endif
+ /* Check and adjust the Shadow-Stack-Pointer. */
+ rdsspd %edx
+ /* And compare it with the saved ssp value. */
+ subl SHADOW_STACK_POINTER_OFFSET(%ecx), %edx
+ je L(skip_ssp)
+ /* 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
+ the number of frames is bigger than 255. */
+ negl %edx
+ shrl $2, %edx
+ /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are
+ restoring Shadow-Stack-Pointer of setjmp's caller, we
+ need to unwind shadow stack by one more frame. */
+ addl $1, %edx
+ movl $255, %ebx
+L(loop):
+ cmpl %ebx, %edx
+ cmovb %edx, %ebx
+ incsspd %ebx
+ subl %ebx, %edx
+ ja L(loop)
+L(skip_ssp):
+#endif
/* Save the return address now. */
movl (JB_PC*4)(%ecx), %edx
/* Get the stack pointer. */
diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile
index c55a43e58d..111ff9ff58 100644
--- a/sysdeps/unix/sysv/linux/x86/Makefile
+++ b/sysdeps/unix/sysv/linux/x86/Makefile
@@ -21,6 +21,5 @@ sysdep_routines += dl-vdso
endif
ifeq ($(subdir),setjmp)
-gen-as-const-headers += jmp_buf-ssp.sym
tests += tst-saved_mask-1
endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
index 8a9f2e1a3c..7eb26fafca 100644
--- a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
+++ b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
@@ -20,7 +20,13 @@
#include <asm-syntax.h>
#include <stap-probe.h>
+/* Don't restore shadow stack register if shadow stack isn't enabled. */
+#if !SHSTK_ENABLED
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
+
#include <sigaltstack-offsets.h>
+#include <jmp_buf-ssp.h>
.section .rodata.str1.1,"aMS",@progbits,1
.type longjmp_msg,@object
@@ -105,6 +111,38 @@ ENTRY(____longjmp_chk)
cfi_restore (%rsi)
.Lok:
+#ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %eax, %eax
+# endif
+ /* Check and adjust the Shadow-Stack-Pointer. */
+ rdsspq %rax
+ /* And compare it with the saved ssp value. */
+ subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax
+ je L(skip_ssp)
+ /* 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
+ the number of frames is bigger than 255. */
+ negq %rax
+ shrq $3, %rax
+ /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are
+ restoring Shadow-Stack-Pointer of setjmp's caller, we
+ need to unwind shadow stack by one more frame. */
+ addq $1, %rax
+ movl $255, %ebx
+L(loop):
+ cmpq %rbx, %rax
+ cmovb %rax, %rbx
+ incsspq %rbx
+ subq %rbx, %rax
+ ja L(loop)
+L(skip_ssp):
+#endif
LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP)
/* We add unwind information for the target here. */
cfi_def_cfa(%rdi, 0)
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index d25d6f0ae4..65292f4032 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -10,5 +10,6 @@ tests-static += tst-get-cpu-features-static
endif
ifeq ($(subdir),setjmp)
+gen-as-const-headers += jmp_buf-ssp.sym
sysdep_routines += __longjmp_cancel
endif
diff --git a/sysdeps/x86/jmp_buf-ssp.sym b/sysdeps/x86/jmp_buf-ssp.sym
new file mode 100644
index 0000000000..1aaaedc9ec
--- /dev/null
+++ b/sysdeps/x86/jmp_buf-ssp.sym
@@ -0,0 +1 @@
+-- FIXME: Define SHADOW_STACK_POINTER_OFFSET to support shadow stack.
diff --git a/sysdeps/x86_64/__longjmp.S b/sysdeps/x86_64/__longjmp.S
index a487e0efd0..d7d123e4bc 100644
--- a/sysdeps/x86_64/__longjmp.S
+++ b/sysdeps/x86_64/__longjmp.S
@@ -17,9 +17,18 @@
#include <sysdep.h>
#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
#include <asm-syntax.h>
#include <stap-probe.h>
+/* Don't restore shadow stack register if
+ 1. Shadow stack isn't enabled. Or
+ 2. __longjmp is defined for __longjmp_cancel.
+ */
+#if !SHSTK_ENABLED || defined __longjmp
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
+
/* Jump to the position specified by ENV, causing the
setjmp call there to return VAL, or 1 if VAL is 0.
void __longjmp (__jmp_buf env, int val). */
@@ -42,6 +51,41 @@ ENTRY(__longjmp)
orq %rax, %r9
# endif
#endif
+#ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %eax, %eax
+# endif
+ /* Check and adjust the Shadow-Stack-Pointer. */
+ /* Get the current ssp. */
+ rdsspq %rax
+ /* And compare it with the saved ssp value. */
+ subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax
+ je L(skip_ssp)
+ /* 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
+ the number of frames is bigger than 255. */
+ negq %rax
+ shrq $3, %rax
+ /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are
+ restoring Shadow-Stack-Pointer of setjmp's caller, we
+ need to unwind shadow stack by one more frame. */
+ addq $1, %rax
+
+ movl $255, %ebx
+L(loop):
+ cmpq %rbx, %rax
+ cmovb %rax, %rbx
+ incsspq %rbx
+ subq %rbx, %rax
+ ja L(loop)
+
+L(skip_ssp):
+#endif
LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP)
/* We add unwind information for the target here. */
cfi_def_cfa(%rdi, 0)
diff --git a/sysdeps/x86_64/setjmp.S b/sysdeps/x86_64/setjmp.S
index e0a648e3e4..78a8bf4644 100644
--- a/sysdeps/x86_64/setjmp.S
+++ b/sysdeps/x86_64/setjmp.S
@@ -18,9 +18,15 @@
#include <sysdep.h>
#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
#include <asm-syntax.h>
#include <stap-probe.h>
+/* Don't save shadow stack register if shadow stack isn't enabled. */
+#if !SHSTK_ENABLED
+# undef SHADOW_STACK_POINTER_OFFSET
+#endif
+
ENTRY (__sigsetjmp)
/* Save registers. */
movq %rbx, (JB_RBX*8)(%rdi)
@@ -54,6 +60,21 @@ ENTRY (__sigsetjmp)
#endif
movq %rax, (JB_PC*8)(%rdi)
+#ifdef SHADOW_STACK_POINTER_OFFSET
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+ /* Check if Shadow Stack is enabled. */
+ testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
+ jz L(skip_ssp)
+# else
+ xorl %eax, %eax
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ rdsspq %rax
+ movq %rax, SHADOW_STACK_POINTER_OFFSET(%rdi)
+# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
+L(skip_ssp):
+# endif
+#endif
#if IS_IN (rtld)
/* In ld.so we never save the signal mask. */
xorl %eax, %eax