x86: Update vfork to pop shadow stack

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.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

	* 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.
This commit is contained in:
H.J. Lu 2018-07-24 05:20:48 -07:00
parent ca027e0f62
commit 3650e1d928
3 changed files with 108 additions and 0 deletions

View File

@ -1,3 +1,16 @@
2018-07-24 H.J. Lu <hongjiu.lu@intel.com>
* 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.
2018-07-24 H.J. Lu <hongjiu.lu@intel.com> 2018-07-24 H.J. Lu <hongjiu.lu@intel.com>
* sysdeps/x86_64/tst-quadmod1.S (func): Add endbr64 if IBT is * sysdeps/x86_64/tst-quadmod1.S (func): Add endbr64 if IBT is

View File

@ -21,6 +21,38 @@
#include <bits/errno.h> #include <bits/errno.h>
#include <tcb-offsets.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. /* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is The calling process is suspended until the new process exits or is
@ -38,16 +70,41 @@ ENTRY (__vfork)
movl $SYS_ify (vfork), %eax movl $SYS_ify (vfork), %eax
int $0x80 int $0x80
#if !SHSTK_ENABLED
/* Jump to the return PC. Don't jump directly since this /* Jump to the return PC. Don't jump directly since this
disturbs the branch target cache. Instead push the return disturbs the branch target cache. Instead push the return
address back on the stack. */ address back on the stack. */
pushl %ecx pushl %ecx
cfi_adjust_cfa_offset (4) cfi_adjust_cfa_offset (4)
#endif
cmpl $-4095, %eax cmpl $-4095, %eax
/* Branch forward if it failed. */ /* Branch forward if it failed. */
jae SYSCALL_ERROR_LABEL 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 ret
PSEUDO_END (__vfork) PSEUDO_END (__vfork)

View File

@ -20,6 +20,21 @@
#include <bits/errno.h> #include <bits/errno.h>
#include <tcb-offsets.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. /* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is The calling process is suspended until the new process exits or is
@ -38,13 +53,36 @@ ENTRY (__vfork)
movl $SYS_ify (vfork), %eax movl $SYS_ify (vfork), %eax
syscall syscall
#if !SHSTK_ENABLED
/* Push back the return PC. */ /* Push back the return PC. */
pushq %rdi pushq %rdi
cfi_adjust_cfa_offset(8) cfi_adjust_cfa_offset(8)
#endif
cmpl $-4095, %eax cmpl $-4095, %eax
jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */ 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. */ /* Normal return. */
ret ret