* [PATCH] Linux/x86: Support shadow stack pointer in setjmp/longjmp
@ 2017-12-18 16:27 H.J. Lu
2017-12-18 17:44 ` Joseph Myers
0 siblings, 1 reply; 11+ messages in thread
From: H.J. Lu @ 2017-12-18 16:27 UTC (permalink / raw)
To: GNU C Library; +Cc: Igor Tsimbalist
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 patch requires:
https://sourceware.org/ml/libc-alpha/2017-12/msg00552.html
https://sourceware.org/ml/libc-alpha/2017-12/msg00208.html
Any comments?
H.J.
---
2017-12-07 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
H.J. Lu <hongjiu.lu@intel.com>
* sysdeps/unix/sysv/linux/i386/____longjmp_chk.S: Include
<jmp_buf-ssp.h>. Restore shadow stack pointer if shadow
stack is enabled.
* sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S: Likewise.
* sysdeps/unix/sysv/linux/i386/__longjmp.S: New file.
* sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S: Likewise.
* sysdeps/unix/sysv/linux/i386/bsd-setjmp.S: Likewise.
* sysdeps/unix/sysv/linux/i386/setjmp.S: Likewise.
* sysdeps/unix/sysv/linux/x86_64/__longjmp.S: Likewise.
* sysdeps/unix/sysv/linux/x86_64/setjmp.S: Likewise.
---
sysdeps/unix/sysv/linux/i386/____longjmp_chk.S | 36 +++++-
sysdeps/unix/sysv/linux/i386/__longjmp.S | 141 +++++++++++++++++++++++
sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S | 72 ++++++++++++
sysdeps/unix/sysv/linux/i386/bsd-setjmp.S | 82 +++++++++++++
sysdeps/unix/sysv/linux/i386/setjmp.S | 73 ++++++++++++
sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S | 35 ++++++
sysdeps/unix/sysv/linux/x86_64/__longjmp.S | 105 +++++++++++++++++
sysdeps/unix/sysv/linux/x86_64/setjmp.S | 82 +++++++++++++
8 files changed, 625 insertions(+), 1 deletion(-)
create mode 100644 sysdeps/unix/sysv/linux/i386/__longjmp.S
create mode 100644 sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S
create mode 100644 sysdeps/unix/sysv/linux/i386/bsd-setjmp.S
create mode 100644 sysdeps/unix/sysv/linux/i386/setjmp.S
create mode 100644 sysdeps/unix/sysv/linux/x86_64/__longjmp.S
create mode 100644 sysdeps/unix/sysv/linux/x86_64/setjmp.S
diff --git a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
index 2e4427abc8..3c2d94e52b 100644
--- a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
+++ b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
@@ -19,7 +19,7 @@
#include <jmpbuf-offsets.h>
#include <asm-syntax.h>
#include <stap-probe.h>
-
+#include <jmp_buf-ssp.h>
.section .rodata.str1.1,"aMS",@progbits,1
.type longjmp_msg,@object
@@ -46,6 +46,40 @@ longjmp_msg:
ENTRY (____longjmp_chk)
movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */
+#ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %gs:FEATURE_1_OFFSET
+ jz .Lnoadj
+# 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 .Lnoadj
+ /* 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
+ cmpl $255, %edx
+ jbe .Lonetime
+.Loopadj:
+ incsspd %edx
+ subl $255, %edx
+ cmpl $255, %edx
+ ja .Loopadj
+.Lonetime:
+ incsspd %edx
+.Lnoadj:
+#endif
/* Save the return address now. */
movl (JB_PC*4)(%ecx), %edx
/* Get the stack pointer. */
diff --git a/sysdeps/unix/sysv/linux/i386/__longjmp.S b/sysdeps/unix/sysv/linux/i386/__longjmp.S
new file mode 100644
index 0000000000..20eeced02e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/__longjmp.S
@@ -0,0 +1,141 @@
+/* longjmp for Linux/i386 with shadow stack support.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <asm-syntax.h>
+#include <stap-probe.h>
+#include <jmp_buf-ssp.h>
+
+ .text
+ENTRY (__longjmp)
+#ifdef PTR_DEMANGLE
+ movl 4(%esp), %eax /* User's jmp_buf in %eax. */
+
+# ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %gs:FEATURE_1_OFFSET
+ jz .Lnoadj
+# 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(%eax), %edx
+ je .Lnoadj
+ /* 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
+ cmpl $255, %edx
+ jbe .Lonetime
+.Loopadj:
+ incsspd %edx
+ subl $255, %edx
+ cmpl $255, %edx
+ ja .Loopadj
+.Lonetime:
+ incsspd %edx
+.Lnoadj:
+# endif
+ /* Save the return address now. */
+ movl (JB_PC*4)(%eax), %edx
+ /* Get the stack pointer. */
+ movl (JB_SP*4)(%eax), %ecx
+ PTR_DEMANGLE (%edx)
+ PTR_DEMANGLE (%ecx)
+ LIBC_PROBE (longjmp, 3, 4@%eax, -4@8(%esp), 4@%edx)
+ cfi_def_cfa(%eax, 0)
+ cfi_register(%eip, %edx)
+ cfi_register(%esp, %ecx)
+ cfi_offset(%ebx, JB_BX*4)
+ cfi_offset(%esi, JB_SI*4)
+ cfi_offset(%edi, JB_DI*4)
+ cfi_offset(%ebp, JB_BP*4)
+ /* Restore registers. */
+ movl (JB_BX*4)(%eax), %ebx
+ movl (JB_SI*4)(%eax), %esi
+ movl (JB_DI*4)(%eax), %edi
+ movl (JB_BP*4)(%eax), %ebp
+ cfi_restore(%ebx)
+ cfi_restore(%esi)
+ cfi_restore(%edi)
+ cfi_restore(%ebp)
+
+ LIBC_PROBE (longjmp_target, 3, 4@%eax, -4@8(%esp), 4@%edx)
+ movl 8(%esp), %eax /* Second argument is return value. */
+ movl %ecx, %esp
+#else
+ movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */
+ movl 8(%esp), %eax /* Second argument is return value. */
+# ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %gs:FEATURE_1_OFFSET
+ jz .Lnoadj
+# 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 .Lnoadj
+ /* 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
+ cmpl $255, %edx
+ jbe .Lonetime
+.Loopadj:
+ incsspd %edx
+ subl $255, %edx
+ cmpl $255, %edx
+ ja .Loopadj
+.Lonetime:
+ incsspd %edx
+.Lnoadj:
+# endif
+ /* Save the return address now. */
+ movl (JB_PC*4)(%ecx), %edx
+ LIBC_PROBE (longjmp, 3, 4@%ecx, -4@%eax, 4@%edx)
+ /* Restore registers. */
+ movl (JB_BX*4)(%ecx), %ebx
+ movl (JB_SI*4)(%ecx), %esi
+ movl (JB_DI*4)(%ecx), %edi
+ movl (JB_BP*4)(%ecx), %ebp
+ movl (JB_SP*4)(%ecx), %esp
+ LIBC_PROBE (longjmp_target, 3, 4@%ecx, -4@%ecx, 4@%edx)
+#endif
+ /* Jump to saved PC. */
+ jmp *%edx
+END (__longjmp)
diff --git a/sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S b/sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S
new file mode 100644
index 0000000000..9cdd969397
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S
@@ -0,0 +1,72 @@
+/* BSD `_setjmp' entry point to `sigsetjmp (..., 0)'. Linux/i386 version
+ with shadow stack support.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This just does a tail-call to `__sigsetjmp (ARG, 0)'.
+ We cannot do it in C because it must be a tail-call, so frame-unwinding
+ in setjmp doesn't clobber the state restored by longjmp. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <stap-probe.h>
+#include <jmp_buf-ssp.h>
+
+#define PARMS 4 /* no space for saved regs */
+#define JMPBUF PARMS
+#define SIGMSK JMPBUF+4
+
+ENTRY (_setjmp)
+
+ xorl %eax, %eax
+ movl JMPBUF(%esp), %edx
+
+ /* Save registers. */
+ movl %ebx, (JB_BX*4)(%edx)
+ movl %esi, (JB_SI*4)(%edx)
+ movl %edi, (JB_DI*4)(%edx)
+ leal JMPBUF(%esp), %ecx /* Save SP as it will be after we return. */
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%ecx)
+#endif
+ movl %ecx, (JB_SP*4)(%edx)
+ movl 0(%esp), %ecx /* Save PC we are returning to now. */
+ LIBC_PROBE (setjmp, 3, 4@%edx, -4@$0, 4@%ecx)
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%ecx)
+#endif
+ movl %ecx, (JB_PC*4)(%edx)
+ movl %ebp, (JB_BP*4)(%edx) /* Save caller's frame pointer. */
+
+ movl %eax, JB_SIZE(%edx) /* No signal mask set. */
+#ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %gs:FEATURE_1_OFFSET
+ jz .Lskip_ssp
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ xorl %ecx, %ecx
+ rdsspd %ecx
+ movl %ecx, SHADOW_STACK_POINTER_OFFSET(%edx)
+# if IS_IN (libc) && defined SHARED
+.Lskip_ssp:
+# endif
+#endif
+ ret
+END (_setjmp)
+libc_hidden_def (_setjmp)
diff --git a/sysdeps/unix/sysv/linux/i386/bsd-setjmp.S b/sysdeps/unix/sysv/linux/i386/bsd-setjmp.S
new file mode 100644
index 0000000000..a66a5a1050
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/bsd-setjmp.S
@@ -0,0 +1,82 @@
+/* BSD `setjmp' entry point to `sigsetjmp (..., 1)'. Linux/i386 version
+ with shadow stack support.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This just does a tail-call to `__sigsetjmp (ARG, 1)'.
+ We cannot do it in C because it must be a tail-call, so frame-unwinding
+ in setjmp doesn't clobber the state restored by longjmp. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <stap-probe.h>
+#include <jmp_buf-ssp.h>
+
+#define PARMS 4 /* no space for saved regs */
+#define JMPBUF PARMS
+#define SIGMSK JMPBUF+4
+
+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
+ PLT which is what we cannot use here. */
+
+ movl JMPBUF(%esp), %eax
+
+ /* Save registers. */
+ movl %ebx, (JB_BX*4)(%eax)
+ movl %esi, (JB_SI*4)(%eax)
+ movl %edi, (JB_DI*4)(%eax)
+ leal JMPBUF(%esp), %ecx /* Save SP as it will be after we return. */
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%ecx)
+#endif
+ movl %ecx, (JB_SP*4)(%eax)
+ movl 0(%esp), %ecx /* Save PC we are returning to now. */
+ LIBC_PROBE (setjmp, 3, 4@%eax, -4@$1, 4@%ecx)
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%ecx)
+#endif
+ movl %ecx, (JB_PC*4)(%eax)
+ movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */
+#ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %gs:FEATURE_1_OFFSET
+ jz .Lskip_ssp
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ xorl %ecx, %ecx
+ rdsspd %ecx
+ movl %ecx, SHADOW_STACK_POINTER_OFFSET(%eax)
+# if IS_IN (libc) && defined SHARED
+.Lskip_ssp:
+# endif
+#endif
+
+ /* Call __sigjmp_save. */
+ pushl $1
+ cfi_adjust_cfa_offset (4)
+ pushl 8(%esp)
+ cfi_adjust_cfa_offset (4)
+ call __sigjmp_save
+ popl %ecx
+ cfi_adjust_cfa_offset (-4)
+ popl %edx
+ cfi_adjust_cfa_offset (-4)
+ ret
+END (setjmp)
diff --git a/sysdeps/unix/sysv/linux/i386/setjmp.S b/sysdeps/unix/sysv/linux/i386/setjmp.S
new file mode 100644
index 0000000000..d7f0ade257
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/setjmp.S
@@ -0,0 +1,73 @@
+/* setjmp for Linux/i386 with shadow stack support.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <asm-syntax.h>
+#include <stap-probe.h>
+#include <jmp_buf-ssp.h>
+
+#define PARMS 4 /* no space for saved regs */
+#define JMPBUF PARMS
+#define SIGMSK JMPBUF+4
+
+ENTRY (__sigsetjmp)
+
+ movl JMPBUF(%esp), %eax
+
+ /* Save registers. */
+ movl %ebx, (JB_BX*4)(%eax)
+ movl %esi, (JB_SI*4)(%eax)
+ movl %edi, (JB_DI*4)(%eax)
+ leal JMPBUF(%esp), %ecx /* Save SP as it will be after we return. */
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%ecx)
+#endif
+ movl %ecx, (JB_SP*4)(%eax)
+ movl 0(%esp), %ecx /* Save PC we are returning to now. */
+ LIBC_PROBE (setjmp, 3, 4@%eax, -4@SIGMSK(%esp), 4@%ecx)
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%ecx)
+#endif
+ movl %ecx, (JB_PC*4)(%eax)
+ movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */
+
+#ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %gs:FEATURE_1_OFFSET
+ jz .Lskip_ssp
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ xorl %ecx, %ecx
+ rdsspd %ecx
+ movl %ecx, SHADOW_STACK_POINTER_OFFSET(%eax)
+# if IS_IN (libc) && defined SHARED
+.Lskip_ssp:
+# endif
+#endif
+#if IS_IN (rtld)
+ /* In ld.so we never save the signal mask. */
+ xorl %eax, %eax
+ ret
+#else
+ /* Make a tail call to __sigjmp_save; it takes the same args. */
+ jmp __sigjmp_save
+#endif
+END (__sigsetjmp)
+hidden_def (__sigsetjmp)
diff --git a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
index 2955c56a56..ee4664d916 100644
--- a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
+++ b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S
@@ -21,6 +21,7 @@
#include <stap-probe.h>
#include <sigaltstack-offsets.h>
+#include <jmp_buf-ssp.h>
.section .rodata.str1.1,"aMS",@progbits,1
.type longjmp_msg,@object
@@ -105,6 +106,40 @@ ENTRY(____longjmp_chk)
cfi_restore (%rsi)
.Lok:
+#ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %fs:FEATURE_1_OFFSET
+ jz .Lnoadj
+# endif
+ /* Check and adjust the Shadow-Stack-Pointer. */
+ xorq %rax, %rax
+ /* Get the current ssp. */
+ rdsspq %rax
+ /* And compare it with the saved ssp value. */
+ subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax
+ je .Lnoadj
+ /* 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
+ cmpq $255, %rax
+ jbe .Lonetime
+.Loopadj:
+ incsspq %rax
+ subq $255, %rax
+ cmpq $255, %rax
+ ja .Loopadj
+.Lonetime:
+ incsspq %rax
+.Lnoadj:
+#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/unix/sysv/linux/x86_64/__longjmp.S b/sysdeps/unix/sysv/linux/x86_64/__longjmp.S
new file mode 100644
index 0000000000..f92aa93431
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/__longjmp.S
@@ -0,0 +1,105 @@
+/* longjmp for Linux/x86-64 with shadow stack support.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
+#include <asm-syntax.h>
+#include <stap-probe.h>
+#include <jmp_buf-ssp.h>
+
+/* 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). */
+ .text
+ENTRY(__longjmp)
+ /* Restore registers. */
+ mov (JB_RSP*8)(%rdi),%R8_LP
+ mov (JB_RBP*8)(%rdi),%R9_LP
+ mov (JB_PC*8)(%rdi),%RDX_LP
+#ifdef PTR_DEMANGLE
+ PTR_DEMANGLE (%R8_LP)
+ PTR_DEMANGLE (%R9_LP)
+ PTR_DEMANGLE (%RDX_LP)
+# ifdef __ILP32__
+ /* We ignored the high bits of the %rbp value because only the low
+ bits are mangled. But we cannot presume that %rbp is being used
+ as a pointer and truncate it, so recover the high bits. */
+ movl (JB_RBP*8 + 4)(%rdi), %eax
+ shlq $32, %rax
+ orq %rax, %r9
+# endif
+#endif
+#ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %fs:FEATURE_1_OFFSET
+ jz .Lnoadj
+# endif
+ /* Check and adjust the Shadow-Stack-Pointer. */
+ xorl %eax, %eax
+ /* Get the current ssp. */
+ rdsspq %rax
+ /* And compare it with the saved ssp value. */
+ subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax
+ je .Lnoadj
+ /* 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
+ cmpq $255, %rax
+ jbe .Lonetime
+.Loopadj:
+ incsspq %rax
+ subq $255, %rax
+ cmpq $255, %rax
+ ja .Loopadj
+.Lonetime:
+ incsspq %rax
+.Lnoadj:
+#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)
+ cfi_register(%rsp,%r8)
+ cfi_register(%rbp,%r9)
+ cfi_register(%rip,%rdx)
+ cfi_offset(%rbx,JB_RBX*8)
+ cfi_offset(%r12,JB_R12*8)
+ cfi_offset(%r13,JB_R13*8)
+ cfi_offset(%r14,JB_R14*8)
+ cfi_offset(%r15,JB_R15*8)
+ movq (JB_RBX*8)(%rdi),%rbx
+ movq (JB_R12*8)(%rdi),%r12
+ movq (JB_R13*8)(%rdi),%r13
+ movq (JB_R14*8)(%rdi),%r14
+ movq (JB_R15*8)(%rdi),%r15
+ /* Set return value for setjmp. */
+ mov %esi, %eax
+ mov %R8_LP,%RSP_LP
+ movq %r9,%rbp
+ LIBC_PROBE (longjmp_target, 3,
+ LP_SIZE@%RDI_LP, -4@%eax, LP_SIZE@%RDX_LP)
+ jmpq *%rdx
+END (__longjmp)
diff --git a/sysdeps/unix/sysv/linux/x86_64/setjmp.S b/sysdeps/unix/sysv/linux/x86_64/setjmp.S
new file mode 100644
index 0000000000..0f03d23bb8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/setjmp.S
@@ -0,0 +1,82 @@
+/* setjmp for Linux/x86-64 with shadow stack support.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <jmp_buf-ssp.h>
+#include <asm-syntax.h>
+#include <stap-probe.h>
+#include <jmp_buf-ssp.h>
+
+ENTRY (__sigsetjmp)
+ /* Save registers. */
+ movq %rbx, (JB_RBX*8)(%rdi)
+#ifdef PTR_MANGLE
+# ifdef __ILP32__
+ /* Save the high bits of %rbp first, since PTR_MANGLE will
+ only handle the low bits but we cannot presume %rbp is
+ being used as a pointer and truncate it. Here we write all
+ of %rbp, but the low bits will be overwritten below. */
+ movq %rbp, (JB_RBP*8)(%rdi)
+# endif
+ mov %RBP_LP, %RAX_LP
+ PTR_MANGLE (%RAX_LP)
+ mov %RAX_LP, (JB_RBP*8)(%rdi)
+#else
+ movq %rbp, (JB_RBP*8)(%rdi)
+#endif
+ movq %r12, (JB_R12*8)(%rdi)
+ movq %r13, (JB_R13*8)(%rdi)
+ movq %r14, (JB_R14*8)(%rdi)
+ movq %r15, (JB_R15*8)(%rdi)
+ lea 8(%rsp), %RDX_LP /* Save SP as it will be after we return. */
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%RDX_LP)
+#endif
+ movq %rdx, (JB_RSP*8)(%rdi)
+ mov (%rsp), %RAX_LP /* Save PC we are returning to now. */
+ LIBC_PROBE (setjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RAX_LP)
+#ifdef PTR_MANGLE
+ PTR_MANGLE (%RAX_LP)
+#endif
+ movq %rax, (JB_PC*8)(%rdi)
+
+#ifdef __SHSTK__
+# if IS_IN (libc) && defined SHARED
+ /* Check if Shadow Stack is enabled. */
+ testl $(1 << 1), %fs:FEATURE_1_OFFSET
+ jz .Lskip_ssp
+# endif
+ /* Get the current Shadow-Stack-Pointer and save it. */
+ xorl %eax, %eax
+ rdsspq %rax
+ movq %rax, SHADOW_STACK_POINTER_OFFSET(%rdi)
+# if IS_IN (libc) && defined SHARED
+.Lskip_ssp:
+# endif
+#endif
+#if IS_IN (rtld)
+ /* In ld.so we never save the signal mask. */
+ xorl %eax, %eax
+ retq
+#else
+ /* Make a tail call to __sigjmp_save; it takes the same args. */
+ jmp __sigjmp_save
+#endif
+END (__sigsetjmp)
+hidden_def (__sigsetjmp)
--
2.14.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Linux/x86: Support shadow stack pointer in setjmp/longjmp
2017-12-18 16:27 [PATCH] Linux/x86: Support shadow stack pointer in setjmp/longjmp H.J. Lu
@ 2017-12-18 17:44 ` Joseph Myers
[not found] ` <CAMe9rOr3gEyaJZ7ukNTY=MiSdWnPbmLOqduodyk3Mx8Qn9J58w@mail.gmail.com>
0 siblings, 1 reply; 11+ messages in thread
From: Joseph Myers @ 2017-12-18 17:44 UTC (permalink / raw)
To: H.J. Lu; +Cc: GNU C Library, Igor Tsimbalist
On Mon, 18 Dec 2017, H.J. Lu wrote:
> * sysdeps/unix/sysv/linux/i386/__longjmp.S: New file.
> * sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S: Likewise.
> * sysdeps/unix/sysv/linux/i386/bsd-setjmp.S: Likewise.
> * sysdeps/unix/sysv/linux/i386/setjmp.S: Likewise.
> * sysdeps/unix/sysv/linux/x86_64/__longjmp.S: Likewise.
> * sysdeps/unix/sysv/linux/x86_64/setjmp.S: Likewise.
Why are all these files Linux-specific? ____longjmp_chk is Linux-specific
because it does a sysaltstack syscall, but I don't see anything
OS-specific in these files. Why shouldn't shadow stack support be
available for all OSes on these architectures?
Is support for the relevant instructions available in all binutils
versions supported for building glibc? If not, does __SHSTK__ being
defined guarantee that GCC was built with a binutils version with the
required support, or do we need additional configure checks for binutils
support?
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2017-12-19 18:36 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-18 16:27 [PATCH] Linux/x86: Support shadow stack pointer in setjmp/longjmp H.J. Lu
2017-12-18 17:44 ` Joseph Myers
[not found] ` <CAMe9rOr3gEyaJZ7ukNTY=MiSdWnPbmLOqduodyk3Mx8Qn9J58w@mail.gmail.com>
2017-12-18 18:09 ` H.J. Lu
2017-12-18 18:25 ` Joseph Myers
2017-12-18 20:22 ` H.J. Lu
2017-12-19 16:41 ` H.J. Lu
2017-12-19 18:20 ` Zack Weinberg
2017-12-19 18:26 ` H.J. Lu
2017-12-19 18:33 ` Joseph Myers
2017-12-19 18:36 ` H.J. Lu
2017-12-19 18:26 ` Joseph Myers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).