This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
PING^1: [PATCH 08/24] x86: Update vfork to pop shadow stack
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>, "Carlos O'Donell" <carlos at redhat dot com>
- Date: Tue, 17 Jul 2018 20:13:47 -0700
- Subject: PING^1: [PATCH 08/24] x86: Update vfork to pop shadow stack
On Wed, Jun 13, 2018 at 8:31 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> Since we can't change return address on shadow stack, if shadow stack
> is in use, we need to pop shadow stack and jump back to caller directly.
>
> * 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.
> ---
> sysdeps/unix/sysv/linux/i386/vfork.S | 54 ++++++++++++++++++++++++++
> sysdeps/unix/sysv/linux/x86_64/vfork.S | 35 +++++++++++++++++
> 2 files changed, 89 insertions(+)
>
> diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S
> index 8f40d02d09..06d834d632 100644
> --- a/sysdeps/unix/sysv/linux/i386/vfork.S
> +++ b/sysdeps/unix/sysv/linux/i386/vfork.S
> @@ -21,6 +21,35 @@
> #include <bits/errno.h>
> #include <tcb-offsets.h>
>
> +#if defined __CET__ && (__CET__ & 2) != 0
> +/* When shadow stack is in use, we need to pop shadow stack and jump
> + back to caller directly. */
> +# 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 +67,41 @@ ENTRY (__vfork)
> movl $SYS_ify (vfork), %eax
> int $0x80
>
> +#if !defined __CET__ || (__CET__ & 2) == 0
> /* 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 defined __CET__ && (__CET__ & 2) != 0
> +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..cab3ad34a0 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/vfork.S
> +++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S
> @@ -20,6 +20,18 @@
> #include <bits/errno.h>
> #include <tcb-offsets.h>
>
> +#if defined __CET__ && (__CET__ & 2) != 0
> +/* When shadow stack is in use, we need to pop shadow stack and jump
> + back to caller directly. */
> +# 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 +50,36 @@ ENTRY (__vfork)
> movl $SYS_ify (vfork), %eax
> syscall
>
> +#if !defined __CET__ || (__CET__ & 2) == 0
> /* 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 defined __CET__ && (__CET__ & 2) != 0
> +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
>
> --
> 2.17.1
>
PING.
--
H.J.