From patchwork Sat Jul 21 14:20:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 28545 Received: (qmail 81891 invoked by alias); 21 Jul 2018 14:20:41 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 81724 invoked by uid 89); 21 Jul 2018 14:20:41 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.8 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.2 spammy=cmpl, HX-Received:sk:d128-v6, HX-Received:3686, 1 X-HELO: mail-pf1-f181.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=w+hRud2Gidc6SzxR9Mp2I1mxr6p+AzEaYK08ETBCQqM=; b=FsZSanLr6U+7yQ7lL3fEgCK+zsGzw7I2m38WHec/oVXQ19Nvtb/eyn1lZdNtuYpPou +3BbIO17cF7kZ/zu5XCrjw6kwqAFxx0fpCQVLbyWfqirCKDAbhzBXnIcy6ZyWQnjcvYJ n37ti7TPVDV6qLAWHyBVP0I18muzY6PS/4AJq9ton7X9Fxk3R8ExW1waMrFgcDrN71LR vuNc21wPxRdr4fea7E+jKovmHkxurGlkt3p/vRndaSsr6P2sB4aUKgqxwGlliUSbOh4s c0Q0TuLPeLUVYiNNRYPVD3iICi35lQ84AKKm3iWQF092hOoFkqk0pL/ZcYhuVe44pRc3 StkA== Return-Path: From: "H.J. Lu" To: libc-alpha@sourceware.org Cc: Carlos O'Donell Subject: [PATCH 01/12] x86: Update vfork to pop shadow stack Date: Sat, 21 Jul 2018 07:20:24 -0700 Message-Id: <20180721142035.21059-2-hjl.tools@gmail.com> In-Reply-To: <20180721142035.21059-1-hjl.tools@gmail.com> References: <20180721142035.21059-1-hjl.tools@gmail.com> 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. Reviewed-by: Carlos O'Donell --- 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..a75436157e 100644 --- a/sysdeps/unix/sysv/linux/i386/vfork.S +++ b/sysdeps/unix/sysv/linux/i386/vfork.S @@ -21,6 +21,35 @@ #include #include +#if SHSTK_ENABLED +/* 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 !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..a6d6280bd2 100644 --- a/sysdeps/unix/sysv/linux/x86_64/vfork.S +++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S @@ -20,6 +20,18 @@ #include #include +#if SHSTK_ENABLED +/* 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 !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