diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/vfork.S | 57 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/x86_64/vfork.S | 38 |
3 files changed, 108 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog index 2a1a53d9df..8b892eb686 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 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> + * sysdeps/x86_64/tst-quadmod1.S (func): Add endbr64 if IBT is enabled. (foo): Likewise. diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S index 8f40d02d09..ce6dbfac48 100644 --- a/sysdeps/unix/sysv/linux/i386/vfork.S +++ b/sysdeps/unix/sysv/linux/i386/vfork.S @@ -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 @@ -38,16 +70,41 @@ ENTRY (__vfork) 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) +#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) diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S index e4c8269e3d..8f1ca9f836 100644 --- a/sysdeps/unix/sysv/linux/x86_64/vfork.S +++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S @@ -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 @@ -38,13 +53,36 @@ ENTRY (__vfork) movl $SYS_ify (vfork), %eax syscall +#if !SHSTK_ENABLED /* 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 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 |