diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-12-27 18:56:13 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-12-27 18:57:13 +0000 |
commit | 82dd75a7f436a19047325d62182590c9f9e23a78 (patch) | |
tree | 60ca20c8cf2b0d178d84725c0715471f76df97e1 /sysdeps/unix/sysv/linux/i386/vfork.S | |
parent | 0bbb676a2342367c4e52b35e890f24667dabb348 (diff) | |
parent | 963c37d5c0eb62b38f8764b23931c0dcdd497a13 (diff) |
Merge commit 'refs/top-bases/t/tls' into t/tls
Diffstat (limited to 'sysdeps/unix/sysv/linux/i386/vfork.S')
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/vfork.S | 78 |
1 files changed, 58 insertions, 20 deletions
diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S index 7a1d3373bb..ce6dbfac48 100644 --- a/sysdeps/unix/sysv/linux/i386/vfork.S +++ b/sysdeps/unix/sysv/linux/i386/vfork.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1999-2016 Free Software Foundation, Inc. +/* Copyright (C) 1999-2018 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Andreas Schwab <schwab@gnu.org>. @@ -21,6 +21,38 @@ #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 +# 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 @@ -34,39 +66,45 @@ ENTRY (__vfork) cfi_adjust_cfa_offset (-4) cfi_register (%eip, %ecx) - /* Save the TCB-cached PID away in %edx, 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 %gs:PID, %edx - movl %edx, %eax - negl %eax - jne 1f - movl $0x80000000, %eax -1: movl %eax, %gs:PID - - /* Stuff the syscall number in EAX and enter into the kernel. */ movl $SYS_ify (vfork), %eax int $0x80 +#if !SHSTK_ENABLED /* 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) - - /* 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. */ - testl %eax, %eax - je 1f - movl %edx, %gs:PID -1: +#endif cmpl $-4095, %eax /* Branch forward if it failed. */ jae SYSCALL_ERROR_LABEL +#if SHSTK_ENABLED +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) |