Message ID | 20180713132252.GC2606@gmail.com |
---|---|
State | New |
Headers | show |
Series | V2: [PATCH 02/24] x86: Support shadow stack pointer in setjmp/longjmp | expand |
On 07/13/2018 09:22 AM, H.J. Lu wrote: > On Thu, Jul 12, 2018 at 02:13:21PM -0400, Carlos O'Donell wrote: >> On 06/13/2018 11:31 AM, H.J. Lu wrote: >>> 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 so that it works with the old smaller cancel_jmp_buf which >>> doesn't have space for shadow stack pointer. >> >> This comment can't be accurate. For the older smaller cancel_jmp_buf >> we found another way to solve this because you just don't restore the >> shadowstack since we're jumping out through the unwinder. So we only >> need this logically for setjmp/longjmp and *context functions? >> >> In general this is OK, I'd like to see a v2: >> >> - New accurate commit message. >> - Replace (1 << 1) with meaningful macro constants that help a future >> reader identify which FEATURE_1 flag we're looking at. >> > > Done. > > ... >>> >>> +# ifdef SHADOW_STACK_POINTER_OFFSET >>> +# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET >>> + /* Check if Shadow Stack is enabled. */ >>> + testl $(1 << 1), %gs:FEATURE_1_OFFSET >> >> Please replace all instances of "1" here with some kind of macro >> that actually defines which flag we're checking. >> > > I updated [PATCH 01/24] to add X86_FEATURE_1_IBT and X86_FEATURE_1_SHSTK > in > > https://sourceware.org/ml/libc-alpha/2018-07/msg00375.html > > Here is the V2 patch. OK for master? This is OK for master and 2.28. Thanks for the update and cleanups. Reviewed-by: Carlos O'Donell <carlos@redhat.com> > > H.J. > ---- > 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. > > 2017-12-07 Igor Tsimbalist <igor.v.tsimbalist@intel.com> > H.J. Lu <hongjiu.lu@intel.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. > --- > sysdeps/i386/__longjmp.S | 73 +++++++++++++++++++ > sysdeps/i386/bsd-_setjmp.S | 21 ++++++ > sysdeps/i386/bsd-setjmp.S | 21 ++++++ > sysdeps/i386/setjmp.S | 21 ++++++ > .../unix/sysv/linux/i386/____longjmp_chk.S | 37 ++++++++++ > sysdeps/unix/sysv/linux/x86/Makefile | 1 - > .../unix/sysv/linux/x86_64/____longjmp_chk.S | 38 ++++++++++ > sysdeps/x86/Makefile | 1 + > sysdeps/x86/jmp_buf-ssp.sym | 1 + > sysdeps/x86_64/__longjmp.S | 44 +++++++++++ > sysdeps/x86_64/setjmp.S | 21 ++++++ > 11 files changed, 278 insertions(+), 1 deletion(-) > create mode 100644 sysdeps/x86/jmp_buf-ssp.sym > > 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). */ > @@ -41,6 +50,41 @@ ENTRY(__longjmp) > shlq $32, %rax > 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. */ > 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 >
* H. J. Lu: > + /* Get the current ssp. */ > + rdsspd %edx This moves the required binutils version past current Debian's 2.28. I know we recently increased the minimum make version recently, but binutils 2.28 is still quite new, I think. Could we list the bytes for the instruction explicitly instead?
On Sat, Jul 14, 2018 at 12:57 PM, Florian Weimer <fw@deneb.enyo.de> wrote: > * H. J. Lu: > >> + /* Get the current ssp. */ >> + rdsspd %edx > > This moves the required binutils version past current Debian's 2.28. > > I know we recently increased the minimum make version recently, but > binutils 2.28 is still quite new, I think. > > Could we list the bytes for the instruction explicitly instead? The next patch: https://sourceware.org/ml/libc-alpha/2018-07/msg00266.html has sysdeps/x86/configure.ac: if test x"$enable_cet" = xyes; then # Check if CET can be enabled. AC_CACHE_CHECK(whether CET can be enabled, libc_cv_x86_cet_available, [dnl cat > conftest.c <<EOF #if !defined __CET__ || __CET__ != 3 # error CET isn't available. #endif EOF if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS -fcf-protection -include cet.h conftest.c 1>&AS_MESSAGE_LOG_FD); then libc_cv_x86_cet_available=yes else libc_cv_x86_cet_available=no fi rm -rf conftest*]) if test $libc_cv_x86_cet_available = yes; then enable_cet=yes else if test x"$enable_cet" = xdefault; then enable_cet=no else AC_MSG_ERROR([$CC doesn't support CET]) fi fi fi if test $enable_cet = yes; then # Check if assembler supports CET. AC_CACHE_CHECK(whether $AS supports CET, libc_cv_x86_cet_as, [dnl cat > conftest.s <<EOF incsspd %ecx EOF if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS conftest.s -o conftest.o 1>&AS_MESSAGE_LOG_FD); then libc_cv_x86_cet_as=yes else libc_cv_x86_cet_as=no fi rm -rf conftest*]) if test $libc_cv_x86_cet_as = no; then AC_MSG_ERROR([$AS doesn't support CET]) fi fi LIBC_CONFIG_VAR([enable-cet], [$enable_cet]) You need GCC 8 and binutils with CET to enable CET. If you have an older binutils or GCC, you will get a configure error when --enable-cet is used.
* H. J. Lu: > On Sat, Jul 14, 2018 at 12:57 PM, Florian Weimer <fw@deneb.enyo.de> wrote: >> * H. J. Lu: >> >>> + /* Get the current ssp. */ >>> + rdsspd %edx >> >> This moves the required binutils version past current Debian's 2.28. >> >> I know we recently increased the minimum make version recently, but >> binutils 2.28 is still quite new, I think. >> >> Could we list the bytes for the instruction explicitly instead? > > The next patch: > > https://sourceware.org/ml/libc-alpha/2018-07/msg00266.html > > has sysdeps/x86/configure.ac: We currently have this (as of commit faaee1f07ed25b2779bfd935ffb29f431b80d6d3): ==> sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym <== #include <setjmpP.h> #undef __saved_mask -- SHADOW_STACK_POINTER_OFFSET offsetof(struct __jmp_buf_tag, __saved_mask.__saved.__shadow_stack_pointer) ==> sysdeps/x86/jmp_buf-ssp.sym <== -- FIXME: Define SHADOW_STACK_POINTER_OFFSET to support shadow stack. So SHADOW_STACK_POINTER_OFFSET is defined unconditionally. I don't see how the quoted patch changes that. Making sure that rdssp is only assembled with --enable-cet looks like the right solution, but you need something like #if ENABLE_CET, and not depend on SHADOW_STACK_POINTER_OFFSET being defined.
On Sat, Jul 14, 2018 at 4:07 PM, Florian Weimer <fw@deneb.enyo.de> wrote: > * H. J. Lu: > >> On Sat, Jul 14, 2018 at 12:57 PM, Florian Weimer <fw@deneb.enyo.de> wrote: >>> * H. J. Lu: >>> >>>> + /* Get the current ssp. */ >>>> + rdsspd %edx >>> >>> This moves the required binutils version past current Debian's 2.28. >>> >>> I know we recently increased the minimum make version recently, but >>> binutils 2.28 is still quite new, I think. >>> >>> Could we list the bytes for the instruction explicitly instead? >> >> The next patch: >> >> https://sourceware.org/ml/libc-alpha/2018-07/msg00266.html >> >> has sysdeps/x86/configure.ac: > > We currently have this (as of commit > faaee1f07ed25b2779bfd935ffb29f431b80d6d3): > > ==> sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym <== > #include <setjmpP.h> > #undef __saved_mask > > -- > SHADOW_STACK_POINTER_OFFSET offsetof(struct __jmp_buf_tag, __saved_mask.__saved.__shadow_stack_pointer) > > ==> sysdeps/x86/jmp_buf-ssp.sym <== > -- FIXME: Define SHADOW_STACK_POINTER_OFFSET to support shadow stack. > > So SHADOW_STACK_POINTER_OFFSET is defined unconditionally. I don't > see how the quoted patch changes that. > > Making sure that rdssp is only assembled with --enable-cet looks like > the right solution, but you need something like #if ENABLE_CET, and > not depend on SHADOW_STACK_POINTER_OFFSET being defined. Take sysdeps/x86_64/setjmp.S as example: /* Don't save shadow stack register if shadow stack isn't enabled. */ #if !SHSTK_ENABLED # undef SHADOW_STACK_POINTER_OFFSET #endif ..... Shadow stack pointer is saved/restored only if --enable-cet is used to configure glibc. If you compile glibc with -fcf-protection, but without configuring glibc with --enable-cet, result is undefined.
On Sat, Jul 14, 2018 at 4:15 PM, H.J. Lu <hjl.tools@gmail.com> wrote: > On Sat, Jul 14, 2018 at 4:07 PM, Florian Weimer <fw@deneb.enyo.de> wrote: >> * H. J. Lu: >> >>> On Sat, Jul 14, 2018 at 12:57 PM, Florian Weimer <fw@deneb.enyo.de> wrote: >>>> * H. J. Lu: >>>> >>>>> + /* Get the current ssp. */ >>>>> + rdsspd %edx >>>> >>>> This moves the required binutils version past current Debian's 2.28. >>>> >>>> I know we recently increased the minimum make version recently, but >>>> binutils 2.28 is still quite new, I think. >>>> >>>> Could we list the bytes for the instruction explicitly instead? >>> >>> The next patch: >>> >>> https://sourceware.org/ml/libc-alpha/2018-07/msg00266.html >>> >>> has sysdeps/x86/configure.ac: >> >> We currently have this (as of commit >> faaee1f07ed25b2779bfd935ffb29f431b80d6d3): >> >> ==> sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym <== >> #include <setjmpP.h> >> #undef __saved_mask >> >> -- >> SHADOW_STACK_POINTER_OFFSET offsetof(struct __jmp_buf_tag, __saved_mask.__saved.__shadow_stack_pointer) >> >> ==> sysdeps/x86/jmp_buf-ssp.sym <== >> -- FIXME: Define SHADOW_STACK_POINTER_OFFSET to support shadow stack. >> >> So SHADOW_STACK_POINTER_OFFSET is defined unconditionally. I don't >> see how the quoted patch changes that. >> >> Making sure that rdssp is only assembled with --enable-cet looks like >> the right solution, but you need something like #if ENABLE_CET, and >> not depend on SHADOW_STACK_POINTER_OFFSET being defined. > > Take sysdeps/x86_64/setjmp.S as example: > > /* Don't save shadow stack register if shadow stack isn't enabled. */ > #if !SHSTK_ENABLED > # undef SHADOW_STACK_POINTER_OFFSET > #endif > ..... > > Shadow stack pointer is saved/restored only if --enable-cet is used to > configure glibc. If you compile glibc with -fcf-protection, but without > configuring glibc with --enable-cet, result is undefined. > BTW, it passed build-many-glibcs.py.
* H. J. Lu: >> We currently have this (as of commit >> faaee1f07ed25b2779bfd935ffb29f431b80d6d3): >> >> ==> sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym <== >> #include <setjmpP.h> >> #undef __saved_mask >> >> -- >> SHADOW_STACK_POINTER_OFFSET offsetof(struct __jmp_buf_tag, >> __saved_mask.__saved.__shadow_stack_pointer) >> >> ==> sysdeps/x86/jmp_buf-ssp.sym <== >> -- FIXME: Define SHADOW_STACK_POINTER_OFFSET to support shadow stack. >> >> So SHADOW_STACK_POINTER_OFFSET is defined unconditionally. I don't >> see how the quoted patch changes that. >> >> Making sure that rdssp is only assembled with --enable-cet looks like >> the right solution, but you need something like #if ENABLE_CET, and >> not depend on SHADOW_STACK_POINTER_OFFSET being defined. > > Take sysdeps/x86_64/setjmp.S as example: > > /* Don't save shadow stack register if shadow stack isn't enabled. */ > #if !SHSTK_ENABLED > # undef SHADOW_STACK_POINTER_OFFSET > #endif > ..... > > Shadow stack pointer is saved/restored only if --enable-cet is used to > configure glibc. If you compile glibc with -fcf-protection, but without > configuring glibc with --enable-cet, result is undefined. That doesn't work because <jmp_buf-ssp.h> is included after the #undef. I think you can avoid that by using #if SHTSTK_ENABLED instead of #ifdef SHADOW_STACK_POINTER_OFFSET, which also expresses the intent more accurately. > BTW, it passed build-many-glibcs.py. With binutils 2.28?
On Sun, Jul 15, 2018 at 1:07 AM, Florian Weimer <fw@deneb.enyo.de> wrote: > * H. J. Lu: > >>> We currently have this (as of commit >>> faaee1f07ed25b2779bfd935ffb29f431b80d6d3): >>> >>> ==> sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym <== >>> #include <setjmpP.h> >>> #undef __saved_mask >>> >>> -- >>> SHADOW_STACK_POINTER_OFFSET offsetof(struct __jmp_buf_tag, >>> __saved_mask.__saved.__shadow_stack_pointer) >>> >>> ==> sysdeps/x86/jmp_buf-ssp.sym <== >>> -- FIXME: Define SHADOW_STACK_POINTER_OFFSET to support shadow stack. >>> >>> So SHADOW_STACK_POINTER_OFFSET is defined unconditionally. I don't >>> see how the quoted patch changes that. >>> >>> Making sure that rdssp is only assembled with --enable-cet looks like >>> the right solution, but you need something like #if ENABLE_CET, and >>> not depend on SHADOW_STACK_POINTER_OFFSET being defined. >> >> Take sysdeps/x86_64/setjmp.S as example: >> >> /* Don't save shadow stack register if shadow stack isn't enabled. */ >> #if !SHSTK_ENABLED >> # undef SHADOW_STACK_POINTER_OFFSET >> #endif >> ..... >> >> Shadow stack pointer is saved/restored only if --enable-cet is used to >> configure glibc. If you compile glibc with -fcf-protection, but without >> configuring glibc with --enable-cet, result is undefined. > > That doesn't work because <jmp_buf-ssp.h> is included after the You are right. sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S checks SHTSTK_ENABLED after <jmp_buf-ssp.h> is included. > #undef. I think you can avoid that by using #if SHTSTK_ENABLED > instead of #ifdef SHADOW_STACK_POINTER_OFFSET, which also expresses > the intent more accurately. It is done on purpose. sysdeps/x86_64/__longjmp.S has /* 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 >> BTW, it passed build-many-glibcs.py. > > With binutils 2.28? I am checking in this patch. Tested with build-many-glibcs.py using binutils 2.28.
* H. J. Lu: >> #undef. I think you can avoid that by using #if SHTSTK_ENABLED >> instead of #ifdef SHADOW_STACK_POINTER_OFFSET, which also expresses >> the intent more accurately. > > It is done on purpose. sysdeps/x86_64/__longjmp.S has > > /* 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 It's a bit awkward. > Subject: [PATCH] x86_64: Undef SHADOW_STACK_POINTER_OFFSET last > > Since SHADOW_STACK_POINTER_OFFSET is defined in jmp_buf-ssp.h, we must > undef SHADOW_STACK_POINTER_OFFSET after including <jmp_buf-ssp.h>. > > * sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S: Undef > SHADOW_STACK_POINTER_OFFSET after including <jmp_buf-ssp.h>. This looks okay as a fix.
On Sun, Jul 15, 2018 at 12:22 PM, Florian Weimer <fw@deneb.enyo.de> wrote: > * H. J. Lu: > >>> #undef. I think you can avoid that by using #if SHTSTK_ENABLED >>> instead of #ifdef SHADOW_STACK_POINTER_OFFSET, which also expresses >>> the intent more accurately. >> >> It is done on purpose. sysdeps/x86_64/__longjmp.S has >> >> /* 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 > > It's a bit awkward. Linux and Hurd share the same implementation of setjmp/longjmp. But 1. For Linux, SHADOW_STACK_POINTER_OFFSET is always defined regardless if CET is enabled. 2.For Hurd, SHADOW_STACK_POINTER_OFFSET is undefined since it is unknown how to save shadow stack pointer. 3. When CET is enabled, setjmp/longjmp is assembled twice. One preserves shadow stack pointer and the other doesn't. Both versions support IBT. 4. All assembly files are compiled with the same compiler options. SHADOW_STACK_POINTER_OFFSET is used to control if shadow stack pointer should be preserved: 1. If CET isn't enabled, undef SHADOW_STACK_POINTER_OFFSET. 2. If CET is enabled, undef SHADOW_STACK_POINTER_OFFSET when not to preserve shadow stack pointer. >> Subject: [PATCH] x86_64: Undef SHADOW_STACK_POINTER_OFFSET last >> >> Since SHADOW_STACK_POINTER_OFFSET is defined in jmp_buf-ssp.h, we must >> undef SHADOW_STACK_POINTER_OFFSET after including <jmp_buf-ssp.h>. >> >> * sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S: Undef >> SHADOW_STACK_POINTER_OFFSET after including <jmp_buf-ssp.h>. > > This looks okay as a fix. I will check it in. Thanks.
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). */ @@ -41,6 +50,41 @@ ENTRY(__longjmp) shlq $32, %rax 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. */ 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