diff mbox series

V2: [PATCH 02/24] x86: Support shadow stack pointer in setjmp/longjmp

Message ID 20180713132252.GC2606@gmail.com
State New
Headers show
Series V2: [PATCH 02/24] x86: Support shadow stack pointer in setjmp/longjmp | expand

Commit Message

H.J. Lu July 13, 2018, 1:22 p.m. UTC
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?

Thanks.


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

Comments

Carlos O'Donell July 13, 2018, 6:49 p.m. UTC | #1
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
>
Florian Weimer July 14, 2018, 7:57 p.m. UTC | #2
* 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?
H.J. Lu July 14, 2018, 9:03 p.m. UTC | #3
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.
Florian Weimer July 14, 2018, 11:07 p.m. UTC | #4
* 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.
H.J. Lu July 14, 2018, 11:15 p.m. UTC | #5
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.
H.J. Lu July 14, 2018, 11:16 p.m. UTC | #6
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.
Florian Weimer July 15, 2018, 8:07 a.m. UTC | #7
* 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?
H.J. Lu July 15, 2018, 1:54 p.m. UTC | #8
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.
Florian Weimer July 15, 2018, 7:22 p.m. UTC | #9
* 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.
H.J. Lu July 15, 2018, 10 p.m. UTC | #10
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 mbox series

Patch

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