From: "H.J. Lu" <hongjiu.lu@intel.com>
To: GNU C Library <libc-alpha@sourceware.org>
Cc: Igor Tsimbalist <igor.v.tsimbalist@intel.com>
Subject: [PATCH] Linux/x86: Support shadow stack pointer in setjmp/longjmp
Date: Mon, 18 Dec 2017 16:27:00 -0000 [thread overview]
Message-ID: <20171218162753.GA25026@gmail.com> (raw)
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
next reply other threads:[~2017-12-18 16:27 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-12-18 16:27 H.J. Lu [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171218162753.GA25026@gmail.com \
--to=hongjiu.lu@intel.com \
--cc=hjl.tools@gmail.com \
--cc=igor.v.tsimbalist@intel.com \
--cc=libc-alpha@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).