]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
x86: Update vfork to pop shadow stack
authorH.J. Lu <hjl.tools@gmail.com>
Tue, 24 Jul 2018 12:20:48 +0000 (05:20 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 24 Jul 2018 12:21:07 +0000 (05:21 -0700)
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.

ChangeLog
sysdeps/unix/sysv/linux/i386/vfork.S
sysdeps/unix/sysv/linux/x86_64/vfork.S

index 2a1a53d9df5514eb6921b5339fc3bc89f42f66e0..8b892eb686c469927f6b96991cb6227136e21109 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 
        * sysdeps/x86_64/tst-quadmod1.S (func): Add endbr64 if IBT is
index 8f40d02d09e6cc543b41f3ac28db8b56f544a3d2..ce6dbfac481ab64d1aceb583237a9d255989139d 100644 (file)
 #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)
index e4c8269e3ddafed75be2c6259cc695fa9487a109..8f1ca9f836800277bc2a0717446db6ba0390a8cf 100644 (file)
 #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