This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 08/23] x86: Update vfork to pop shadow stack
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: libc-alpha at sourceware dot org
- Cc: Carlos O'Donell <carlos at redhat dot com>
- Date: Tue, 8 May 2018 13:40:06 -0700
- Subject: [PATCH 08/23] x86: Update vfork to pop shadow stack
- References: <20180508204021.31845-1-hjl.tools@gmail.com>
Since we can't change return address on shadow stack, if shadow stack
is in use, we need to pop shadow stack and jump back to caller directly.
* sysdeps/unix/sysv/linux/i386/vfork.S (SYSCALL_ERROR_HANDLER):
Redefine if shadow stack is enabled.
(SYSCALL_ERROR_LABEL): Likewise.
(__vfork): Pop shadow stack and jump back to to caller directly
when shadow stack is in use.
* sysdeps/unix/sysv/linux/x86_64/vfork.S (SYSCALL_ERROR_HANDLER):
Redefine if shadow stack is enabled.
(SYSCALL_ERROR_LABEL): Likewise.
(__vfork): Pop shadow stack and jump back to to caller directly
when shadow stack is in use.
---
sysdeps/unix/sysv/linux/i386/vfork.S | 54 ++++++++++++++++++++++++++
sysdeps/unix/sysv/linux/x86_64/vfork.S | 35 +++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S
index 8f40d02d09..06d834d632 100644
--- a/sysdeps/unix/sysv/linux/i386/vfork.S
+++ b/sysdeps/unix/sysv/linux/i386/vfork.S
@@ -21,6 +21,35 @@
#include <bits/errno.h>
#include <tcb-offsets.h>
+#if defined __CET__ && (__CET__ & 2) != 0
+/* When shadow stack is in use, we need to pop shadow stack and jump
+ back to caller directly. */
+# undef SYSCALL_ERROR_HANDLER
+# ifdef PIC
+# define SYSCALL_ERROR_HANDLER \
+0: \
+ calll .L1; \
+.L1: \
+ popl %edx; \
+.L2: \
+ addl $_GLOBAL_OFFSET_TABLE_ + (.L2 - .L1), %edx; \
+ movl __libc_errno@gotntpoff(%edx), %edx; \
+ negl %eax; \
+ movl %eax, %gs:(%edx); \
+ orl $-1, %eax; \
+ jmp 1b;
+# else
+# define SYSCALL_ERROR_HANDLER \
+0: \
+ movl __libc_errno@indntpoff, %edx; \
+ negl %eax; \
+ movl %eax, %gs:(%edx); \
+ orl $-1, %eax; \
+ jmp 1b;
+# endif
+# undef SYSCALL_ERROR_LABEL
+# define SYSCALL_ERROR_LABEL 0f
+#endif
/* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is
@@ -38,16 +67,41 @@ ENTRY (__vfork)
movl $SYS_ify (vfork), %eax
int $0x80
+#if !defined __CET__ || (__CET__ & 2) == 0
/* Jump to the return PC. Don't jump directly since this
disturbs the branch target cache. Instead push the return
address back on the stack. */
pushl %ecx
cfi_adjust_cfa_offset (4)
+#endif
cmpl $-4095, %eax
/* Branch forward if it failed. */
jae SYSCALL_ERROR_LABEL
+#if defined __CET__ && (__CET__ & 2) != 0
+1:
+ /* Check if shadow stack is in use. */
+ xorl %edx, %edx
+ rdsspd %edx
+ testl %edx, %edx
+ /* Normal return if shadow stack isn't in use. */
+ je L(no_shstk)
+
+ /* Pop return address from shadow stack and jump back to caller
+ directly. */
+ movl $1, %edx
+ incsspd %edx
+ jmp *%ecx
+
+L(no_shstk):
+ /* Jump to the return PC. Don't jump directly since this
+ disturbs the branch target cache. Instead push the return
+ address back on the stack. */
+ pushl %ecx
+ cfi_adjust_cfa_offset (4)
+#endif
+
ret
PSEUDO_END (__vfork)
diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S
index e4c8269e3d..cab3ad34a0 100644
--- a/sysdeps/unix/sysv/linux/x86_64/vfork.S
+++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S
@@ -20,6 +20,18 @@
#include <bits/errno.h>
#include <tcb-offsets.h>
+#if defined __CET__ && (__CET__ & 2) != 0
+/* When shadow stack is in use, we need to pop shadow stack and jump
+ back to caller directly. */
+# undef SYSCALL_ERROR_HANDLER
+# define SYSCALL_ERROR_HANDLER \
+0: \
+ SYSCALL_SET_ERRNO; \
+ or $-1, %RAX_LP; \
+ jmp 1b;
+# undef SYSCALL_ERROR_LABEL
+# define SYSCALL_ERROR_LABEL 0f
+#endif
/* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is
@@ -38,13 +50,36 @@ ENTRY (__vfork)
movl $SYS_ify (vfork), %eax
syscall
+#if !defined __CET__ || (__CET__ & 2) == 0
/* Push back the return PC. */
pushq %rdi
cfi_adjust_cfa_offset(8)
+#endif
cmpl $-4095, %eax
jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */
+#if defined __CET__ && (__CET__ & 2) != 0
+1:
+ /* Check if shadow stack is in use. */
+ xorl %esi, %esi
+ rdsspq %rsi
+ testq %rsi, %rsi
+ /* Normal return if shadow stack isn't in use. */
+ je L(no_shstk)
+
+ /* Pop return address from shadow stack and jump back to caller
+ directly. */
+ movl $1, %esi
+ incsspq %rsi
+ jmp *%rdi
+
+L(no_shstk):
+ /* Push back the return PC. */
+ pushq %rdi
+ cfi_adjust_cfa_offset(8)
+#endif
+
/* Normal return. */
ret
--
2.17.0