summaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux/x86_64/vfork.S
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/x86_64/vfork.S')
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/vfork.S58
1 files changed, 39 insertions, 19 deletions
diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S
index 8332ade9fb..8f1ca9f836 100644
--- a/sysdeps/unix/sysv/linux/x86_64/vfork.S
+++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2018 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
@@ -20,6 +20,21 @@
#include <bits/errno.h>
#include <tcb-offsets.h>
+#if SHSTK_ENABLED
+/* The shadow stack prevents us from pushing the saved return PC onto
+ the stack and returning normally. Instead we pop the shadow stack
+ and return directly. This is the safest way to return and ensures
+ any stack manipulations done by the vfork'd child doesn't cause the
+ parent to terminate when CET is enabled. */
+# 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
@@ -34,35 +49,40 @@ ENTRY (__vfork)
cfi_adjust_cfa_offset(-8)
cfi_register(%rip, %rdi)
- /* Save the TCB-cached PID away in %esi, and then negate the TCB
- field. But if it's zero, set it to 0x80000000 instead. See
- raise.c for the logic that relies on this value. */
- movl %fs:PID, %esi
- movl $0x80000000, %ecx
- movl %esi, %edx
- negl %edx
- cmove %ecx, %edx
- movl %edx, %fs:PID
-
/* Stuff the syscall number in RAX and enter into the kernel. */
movl $SYS_ify (vfork), %eax
syscall
+#if !SHSTK_ENABLED
/* Push back the return PC. */
pushq %rdi
cfi_adjust_cfa_offset(8)
-
- /* Restore the original value of the TCB cache of the PID, if we're
- the parent. But in the child (syscall return value equals zero),
- leave things as they are. */
- testq %rax, %rax
- je 1f
- movl %esi, %fs:PID
-1:
+#endif
cmpl $-4095, %eax
jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */
+#if SHSTK_ENABLED
+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