From patchwork Mon Dec 18 16:27:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 850162 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-88259-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="YTI/k7vE"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3z0mfx1CWDz9s03 for ; Tue, 19 Dec 2017 03:28:08 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:cc:subject:message-id:reply-to :mime-version:content-type; q=dns; s=default; b=N29881ZjksKi5bbi Ev1Unq7TdOBiLMptndPjBDBgnyvX8K75TGMFa+9ThicxfC8nNDjYIDWfEc8N/xUM VejzmkUbpQeE+87geYZoCqnVIfN1KZxSCpODsYwus+Sy4k+dcg1OnIWiMYvrTkbE KUXigNHsl9RYT/W23rMU0rt+TRQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:cc:subject:message-id:reply-to :mime-version:content-type; s=default; bh=bk4TZqFqya52X/b75zVoTX zOeNY=; b=YTI/k7vEwBJjxfuMr51uPx72ufi3uVyN+AtkOCHgv4IVpew9pXLRhZ Zol7XrHwmGO+qRqIxk0N4ll6CP8YaKFAaSM9sqFnJAM8da5LORggAYrKeDHCYLHB edrN3bklE9ri/84wBEFN1jsBOCHwr2sO+644pxfJY8Eo29kkYVJV0= Received: (qmail 77205 invoked by alias); 18 Dec 2017 16:27:59 -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 77194 invoked by uid 89); 18 Dec 2017 16:27:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, NO_DNS_FOR_FROM, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy= X-HELO: mga06.intel.com X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False X-ExtLoop1: 1 Date: Mon, 18 Dec 2017 08:27:53 -0800 From: "H.J. Lu" To: GNU C Library Cc: Igor Tsimbalist Subject: [PATCH] Linux/x86: Support shadow stack pointer in setjmp/longjmp Message-ID: <20171218162753.GA25026@gmail.com> Reply-To: "H.J. Lu" MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.1 (2017-09-22) Save and restore shadow stack pointer in setjmp and longjmp to support shadow stack in Intel CET. Use feature_1 in tcbhead_t to check if shadow stack is enabled before saving and restoring shadow stack pointer so that it works with the old smaller cancel_jmp_buf which doesn't have space for shadow stack pointer. This patch requires: https://sourceware.org/ml/libc-alpha/2017-12/msg00552.html https://sourceware.org/ml/libc-alpha/2017-12/msg00208.html Any comments? H.J. --- 2017-12-07 Igor Tsimbalist H.J. Lu * sysdeps/unix/sysv/linux/i386/____longjmp_chk.S: Include . Restore shadow stack pointer if shadow stack is enabled. * sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S: Likewise. * sysdeps/unix/sysv/linux/i386/__longjmp.S: New file. * sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S: Likewise. * sysdeps/unix/sysv/linux/i386/bsd-setjmp.S: Likewise. * sysdeps/unix/sysv/linux/i386/setjmp.S: Likewise. * sysdeps/unix/sysv/linux/x86_64/__longjmp.S: Likewise. * sysdeps/unix/sysv/linux/x86_64/setjmp.S: Likewise. --- sysdeps/unix/sysv/linux/i386/____longjmp_chk.S | 36 +++++- sysdeps/unix/sysv/linux/i386/__longjmp.S | 141 +++++++++++++++++++++++ sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S | 72 ++++++++++++ sysdeps/unix/sysv/linux/i386/bsd-setjmp.S | 82 +++++++++++++ sysdeps/unix/sysv/linux/i386/setjmp.S | 73 ++++++++++++ sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S | 35 ++++++ sysdeps/unix/sysv/linux/x86_64/__longjmp.S | 105 +++++++++++++++++ sysdeps/unix/sysv/linux/x86_64/setjmp.S | 82 +++++++++++++ 8 files changed, 625 insertions(+), 1 deletion(-) create mode 100644 sysdeps/unix/sysv/linux/i386/__longjmp.S create mode 100644 sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S create mode 100644 sysdeps/unix/sysv/linux/i386/bsd-setjmp.S create mode 100644 sysdeps/unix/sysv/linux/i386/setjmp.S create mode 100644 sysdeps/unix/sysv/linux/x86_64/__longjmp.S create mode 100644 sysdeps/unix/sysv/linux/x86_64/setjmp.S diff --git a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S index 2e4427abc8..3c2d94e52b 100644 --- a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S +++ b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S @@ -19,7 +19,7 @@ #include #include #include - +#include .section .rodata.str1.1,"aMS",@progbits,1 .type longjmp_msg,@object @@ -46,6 +46,40 @@ longjmp_msg: ENTRY (____longjmp_chk) movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */ +#ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %gs:FEATURE_1_OFFSET + jz .Lnoadj +# endif + /* Check and adjust the Shadow-Stack-Pointer. */ + xorl %edx, %edx + /* Get the current ssp. */ + rdsspd %edx + /* And compare it with the saved ssp value. */ + subl SHADOW_STACK_POINTER_OFFSET(%ecx), %edx + je .Lnoadj + /* Count the number of frames to adjust and adjust it + with incssp instruction. The instruction can adjust + the ssp by [0..255] value only thus use a loop if + the number of frames is bigger than 255. */ + negl %edx + shrl $2, %edx + /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are + restoring Shadow-Stack-Pointer of setjmp's caller, we + need to unwind shadow stack by one more frame. */ + addl $1, %edx + cmpl $255, %edx + jbe .Lonetime +.Loopadj: + incsspd %edx + subl $255, %edx + cmpl $255, %edx + ja .Loopadj +.Lonetime: + incsspd %edx +.Lnoadj: +#endif /* Save the return address now. */ movl (JB_PC*4)(%ecx), %edx /* Get the stack pointer. */ diff --git a/sysdeps/unix/sysv/linux/i386/__longjmp.S b/sysdeps/unix/sysv/linux/i386/__longjmp.S new file mode 100644 index 0000000000..20eeced02e --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/__longjmp.S @@ -0,0 +1,141 @@ +/* longjmp for Linux/i386 with shadow stack support. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + + .text +ENTRY (__longjmp) +#ifdef PTR_DEMANGLE + movl 4(%esp), %eax /* User's jmp_buf in %eax. */ + +# ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %gs:FEATURE_1_OFFSET + jz .Lnoadj +# endif + /* Check and adjust the Shadow-Stack-Pointer. */ + xorl %edx, %edx + /* Get the current ssp. */ + rdsspd %edx + /* And compare it with the saved ssp value. */ + subl SHADOW_STACK_POINTER_OFFSET(%eax), %edx + je .Lnoadj + /* Count the number of frames to adjust and adjust it + with incssp instruction. The instruction can adjust + the ssp by [0..255] value only thus use a loop if + the number of frames is bigger than 255. */ + negl %edx + shrl $2, %edx + /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are + restoring Shadow-Stack-Pointer of setjmp's caller, we + need to unwind shadow stack by one more frame. */ + addl $1, %edx + cmpl $255, %edx + jbe .Lonetime +.Loopadj: + incsspd %edx + subl $255, %edx + cmpl $255, %edx + ja .Loopadj +.Lonetime: + incsspd %edx +.Lnoadj: +# endif + /* Save the return address now. */ + movl (JB_PC*4)(%eax), %edx + /* Get the stack pointer. */ + movl (JB_SP*4)(%eax), %ecx + PTR_DEMANGLE (%edx) + PTR_DEMANGLE (%ecx) + LIBC_PROBE (longjmp, 3, 4@%eax, -4@8(%esp), 4@%edx) + cfi_def_cfa(%eax, 0) + cfi_register(%eip, %edx) + cfi_register(%esp, %ecx) + cfi_offset(%ebx, JB_BX*4) + cfi_offset(%esi, JB_SI*4) + cfi_offset(%edi, JB_DI*4) + cfi_offset(%ebp, JB_BP*4) + /* Restore registers. */ + movl (JB_BX*4)(%eax), %ebx + movl (JB_SI*4)(%eax), %esi + movl (JB_DI*4)(%eax), %edi + movl (JB_BP*4)(%eax), %ebp + cfi_restore(%ebx) + cfi_restore(%esi) + cfi_restore(%edi) + cfi_restore(%ebp) + + LIBC_PROBE (longjmp_target, 3, 4@%eax, -4@8(%esp), 4@%edx) + movl 8(%esp), %eax /* Second argument is return value. */ + movl %ecx, %esp +#else + movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */ + movl 8(%esp), %eax /* Second argument is return value. */ +# ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %gs:FEATURE_1_OFFSET + jz .Lnoadj +# endif + /* Check and adjust the Shadow-Stack-Pointer. */ + xorl %edx, %edx + /* Get the current ssp. */ + rdsspd %edx + /* And compare it with the saved ssp value. */ + subl SHADOW_STACK_POINTER_OFFSET(%ecx), %edx + je .Lnoadj + /* Count the number of frames to adjust and adjust it + with incssp instruction. The instruction can adjust + the ssp by [0..255] value only thus use a loop if + the number of frames is bigger than 255. */ + negl %edx + shrl $2, %edx + /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are + restoring Shadow-Stack-Pointer of setjmp's caller, we + need to unwind shadow stack by one more frame. */ + addl $1, %edx + cmpl $255, %edx + jbe .Lonetime +.Loopadj: + incsspd %edx + subl $255, %edx + cmpl $255, %edx + ja .Loopadj +.Lonetime: + incsspd %edx +.Lnoadj: +# endif + /* Save the return address now. */ + movl (JB_PC*4)(%ecx), %edx + LIBC_PROBE (longjmp, 3, 4@%ecx, -4@%eax, 4@%edx) + /* Restore registers. */ + movl (JB_BX*4)(%ecx), %ebx + movl (JB_SI*4)(%ecx), %esi + movl (JB_DI*4)(%ecx), %edi + movl (JB_BP*4)(%ecx), %ebp + movl (JB_SP*4)(%ecx), %esp + LIBC_PROBE (longjmp_target, 3, 4@%ecx, -4@%ecx, 4@%edx) +#endif + /* Jump to saved PC. */ + jmp *%edx +END (__longjmp) diff --git a/sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S b/sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S new file mode 100644 index 0000000000..9cdd969397 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/bsd-_setjmp.S @@ -0,0 +1,72 @@ +/* BSD `_setjmp' entry point to `sigsetjmp (..., 0)'. Linux/i386 version + with shadow stack support. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This just does a tail-call to `__sigsetjmp (ARG, 0)'. + We cannot do it in C because it must be a tail-call, so frame-unwinding + in setjmp doesn't clobber the state restored by longjmp. */ + +#include +#include +#include +#include + +#define PARMS 4 /* no space for saved regs */ +#define JMPBUF PARMS +#define SIGMSK JMPBUF+4 + +ENTRY (_setjmp) + + xorl %eax, %eax + movl JMPBUF(%esp), %edx + + /* Save registers. */ + movl %ebx, (JB_BX*4)(%edx) + movl %esi, (JB_SI*4)(%edx) + movl %edi, (JB_DI*4)(%edx) + leal JMPBUF(%esp), %ecx /* Save SP as it will be after we return. */ +#ifdef PTR_MANGLE + PTR_MANGLE (%ecx) +#endif + movl %ecx, (JB_SP*4)(%edx) + movl 0(%esp), %ecx /* Save PC we are returning to now. */ + LIBC_PROBE (setjmp, 3, 4@%edx, -4@$0, 4@%ecx) +#ifdef PTR_MANGLE + PTR_MANGLE (%ecx) +#endif + movl %ecx, (JB_PC*4)(%edx) + movl %ebp, (JB_BP*4)(%edx) /* Save caller's frame pointer. */ + + movl %eax, JB_SIZE(%edx) /* No signal mask set. */ +#ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %gs:FEATURE_1_OFFSET + jz .Lskip_ssp +# endif + /* Get the current Shadow-Stack-Pointer and save it. */ + xorl %ecx, %ecx + rdsspd %ecx + movl %ecx, SHADOW_STACK_POINTER_OFFSET(%edx) +# if IS_IN (libc) && defined SHARED +.Lskip_ssp: +# endif +#endif + ret +END (_setjmp) +libc_hidden_def (_setjmp) diff --git a/sysdeps/unix/sysv/linux/i386/bsd-setjmp.S b/sysdeps/unix/sysv/linux/i386/bsd-setjmp.S new file mode 100644 index 0000000000..a66a5a1050 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/bsd-setjmp.S @@ -0,0 +1,82 @@ +/* BSD `setjmp' entry point to `sigsetjmp (..., 1)'. Linux/i386 version + with shadow stack support. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This just does a tail-call to `__sigsetjmp (ARG, 1)'. + We cannot do it in C because it must be a tail-call, so frame-unwinding + in setjmp doesn't clobber the state restored by longjmp. */ + +#include +#include +#include +#include + +#define PARMS 4 /* no space for saved regs */ +#define JMPBUF PARMS +#define SIGMSK JMPBUF+4 + +ENTRY (setjmp) + /* Note that we have to use a non-exported symbol in the next + jump since otherwise gas will emit it as a jump through the + PLT which is what we cannot use here. */ + + movl JMPBUF(%esp), %eax + + /* Save registers. */ + movl %ebx, (JB_BX*4)(%eax) + movl %esi, (JB_SI*4)(%eax) + movl %edi, (JB_DI*4)(%eax) + leal JMPBUF(%esp), %ecx /* Save SP as it will be after we return. */ +#ifdef PTR_MANGLE + PTR_MANGLE (%ecx) +#endif + movl %ecx, (JB_SP*4)(%eax) + movl 0(%esp), %ecx /* Save PC we are returning to now. */ + LIBC_PROBE (setjmp, 3, 4@%eax, -4@$1, 4@%ecx) +#ifdef PTR_MANGLE + PTR_MANGLE (%ecx) +#endif + movl %ecx, (JB_PC*4)(%eax) + movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */ +#ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %gs:FEATURE_1_OFFSET + jz .Lskip_ssp +# endif + /* Get the current Shadow-Stack-Pointer and save it. */ + xorl %ecx, %ecx + rdsspd %ecx + movl %ecx, SHADOW_STACK_POINTER_OFFSET(%eax) +# if IS_IN (libc) && defined SHARED +.Lskip_ssp: +# endif +#endif + + /* Call __sigjmp_save. */ + pushl $1 + cfi_adjust_cfa_offset (4) + pushl 8(%esp) + cfi_adjust_cfa_offset (4) + call __sigjmp_save + popl %ecx + cfi_adjust_cfa_offset (-4) + popl %edx + cfi_adjust_cfa_offset (-4) + ret +END (setjmp) diff --git a/sysdeps/unix/sysv/linux/i386/setjmp.S b/sysdeps/unix/sysv/linux/i386/setjmp.S new file mode 100644 index 0000000000..d7f0ade257 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/setjmp.S @@ -0,0 +1,73 @@ +/* setjmp for Linux/i386 with shadow stack support. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +#define PARMS 4 /* no space for saved regs */ +#define JMPBUF PARMS +#define SIGMSK JMPBUF+4 + +ENTRY (__sigsetjmp) + + movl JMPBUF(%esp), %eax + + /* Save registers. */ + movl %ebx, (JB_BX*4)(%eax) + movl %esi, (JB_SI*4)(%eax) + movl %edi, (JB_DI*4)(%eax) + leal JMPBUF(%esp), %ecx /* Save SP as it will be after we return. */ +#ifdef PTR_MANGLE + PTR_MANGLE (%ecx) +#endif + movl %ecx, (JB_SP*4)(%eax) + movl 0(%esp), %ecx /* Save PC we are returning to now. */ + LIBC_PROBE (setjmp, 3, 4@%eax, -4@SIGMSK(%esp), 4@%ecx) +#ifdef PTR_MANGLE + PTR_MANGLE (%ecx) +#endif + movl %ecx, (JB_PC*4)(%eax) + movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */ + +#ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %gs:FEATURE_1_OFFSET + jz .Lskip_ssp +# endif + /* Get the current Shadow-Stack-Pointer and save it. */ + xorl %ecx, %ecx + rdsspd %ecx + movl %ecx, SHADOW_STACK_POINTER_OFFSET(%eax) +# if IS_IN (libc) && defined SHARED +.Lskip_ssp: +# endif +#endif +#if IS_IN (rtld) + /* In ld.so we never save the signal mask. */ + xorl %eax, %eax + ret +#else + /* Make a tail call to __sigjmp_save; it takes the same args. */ + jmp __sigjmp_save +#endif +END (__sigsetjmp) +hidden_def (__sigsetjmp) diff --git a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S index 2955c56a56..ee4664d916 100644 --- a/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S +++ b/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S @@ -21,6 +21,7 @@ #include #include +#include .section .rodata.str1.1,"aMS",@progbits,1 .type longjmp_msg,@object @@ -105,6 +106,40 @@ ENTRY(____longjmp_chk) cfi_restore (%rsi) .Lok: +#ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %fs:FEATURE_1_OFFSET + jz .Lnoadj +# endif + /* Check and adjust the Shadow-Stack-Pointer. */ + xorq %rax, %rax + /* Get the current ssp. */ + rdsspq %rax + /* And compare it with the saved ssp value. */ + subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax + je .Lnoadj + /* Count the number of frames to adjust and adjust it + with incssp instruction. The instruction can adjust + the ssp by [0..255] value only thus use a loop if + the number of frames is bigger than 255. */ + negq %rax + shrq $3, %rax + /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are + restoring Shadow-Stack-Pointer of setjmp's caller, we + need to unwind shadow stack by one more frame. */ + addq $1, %rax + cmpq $255, %rax + jbe .Lonetime +.Loopadj: + incsspq %rax + subq $255, %rax + cmpq $255, %rax + ja .Loopadj +.Lonetime: + incsspq %rax +.Lnoadj: +#endif LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP) /* We add unwind information for the target here. */ cfi_def_cfa(%rdi, 0) diff --git a/sysdeps/unix/sysv/linux/x86_64/__longjmp.S b/sysdeps/unix/sysv/linux/x86_64/__longjmp.S new file mode 100644 index 0000000000..f92aa93431 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/__longjmp.S @@ -0,0 +1,105 @@ +/* longjmp for Linux/x86-64 with shadow stack support. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +/* Jump to the position specified by ENV, causing the + setjmp call there to return VAL, or 1 if VAL is 0. + void __longjmp (__jmp_buf env, int val). */ + .text +ENTRY(__longjmp) + /* Restore registers. */ + mov (JB_RSP*8)(%rdi),%R8_LP + mov (JB_RBP*8)(%rdi),%R9_LP + mov (JB_PC*8)(%rdi),%RDX_LP +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (%R8_LP) + PTR_DEMANGLE (%R9_LP) + PTR_DEMANGLE (%RDX_LP) +# ifdef __ILP32__ + /* We ignored the high bits of the %rbp value because only the low + bits are mangled. But we cannot presume that %rbp is being used + as a pointer and truncate it, so recover the high bits. */ + movl (JB_RBP*8 + 4)(%rdi), %eax + shlq $32, %rax + orq %rax, %r9 +# endif +#endif +#ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %fs:FEATURE_1_OFFSET + jz .Lnoadj +# endif + /* Check and adjust the Shadow-Stack-Pointer. */ + xorl %eax, %eax + /* Get the current ssp. */ + rdsspq %rax + /* And compare it with the saved ssp value. */ + subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax + je .Lnoadj + /* Count the number of frames to adjust and adjust it + with incssp instruction. The instruction can adjust + the ssp by [0..255] value only thus use a loop if + the number of frames is bigger than 255. */ + negq %rax + shrq $3, %rax + /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are + restoring Shadow-Stack-Pointer of setjmp's caller, we + need to unwind shadow stack by one more frame. */ + addq $1, %rax + cmpq $255, %rax + jbe .Lonetime +.Loopadj: + incsspq %rax + subq $255, %rax + cmpq $255, %rax + ja .Loopadj +.Lonetime: + incsspq %rax +.Lnoadj: +#endif + LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP) + /* We add unwind information for the target here. */ + cfi_def_cfa(%rdi, 0) + cfi_register(%rsp,%r8) + cfi_register(%rbp,%r9) + cfi_register(%rip,%rdx) + cfi_offset(%rbx,JB_RBX*8) + cfi_offset(%r12,JB_R12*8) + cfi_offset(%r13,JB_R13*8) + cfi_offset(%r14,JB_R14*8) + cfi_offset(%r15,JB_R15*8) + movq (JB_RBX*8)(%rdi),%rbx + movq (JB_R12*8)(%rdi),%r12 + movq (JB_R13*8)(%rdi),%r13 + movq (JB_R14*8)(%rdi),%r14 + movq (JB_R15*8)(%rdi),%r15 + /* Set return value for setjmp. */ + mov %esi, %eax + mov %R8_LP,%RSP_LP + movq %r9,%rbp + LIBC_PROBE (longjmp_target, 3, + LP_SIZE@%RDI_LP, -4@%eax, LP_SIZE@%RDX_LP) + jmpq *%rdx +END (__longjmp) diff --git a/sysdeps/unix/sysv/linux/x86_64/setjmp.S b/sysdeps/unix/sysv/linux/x86_64/setjmp.S new file mode 100644 index 0000000000..0f03d23bb8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/setjmp.S @@ -0,0 +1,82 @@ +/* setjmp for Linux/x86-64 with shadow stack support. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +ENTRY (__sigsetjmp) + /* Save registers. */ + movq %rbx, (JB_RBX*8)(%rdi) +#ifdef PTR_MANGLE +# ifdef __ILP32__ + /* Save the high bits of %rbp first, since PTR_MANGLE will + only handle the low bits but we cannot presume %rbp is + being used as a pointer and truncate it. Here we write all + of %rbp, but the low bits will be overwritten below. */ + movq %rbp, (JB_RBP*8)(%rdi) +# endif + mov %RBP_LP, %RAX_LP + PTR_MANGLE (%RAX_LP) + mov %RAX_LP, (JB_RBP*8)(%rdi) +#else + movq %rbp, (JB_RBP*8)(%rdi) +#endif + movq %r12, (JB_R12*8)(%rdi) + movq %r13, (JB_R13*8)(%rdi) + movq %r14, (JB_R14*8)(%rdi) + movq %r15, (JB_R15*8)(%rdi) + lea 8(%rsp), %RDX_LP /* Save SP as it will be after we return. */ +#ifdef PTR_MANGLE + PTR_MANGLE (%RDX_LP) +#endif + movq %rdx, (JB_RSP*8)(%rdi) + mov (%rsp), %RAX_LP /* Save PC we are returning to now. */ + LIBC_PROBE (setjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RAX_LP) +#ifdef PTR_MANGLE + PTR_MANGLE (%RAX_LP) +#endif + movq %rax, (JB_PC*8)(%rdi) + +#ifdef __SHSTK__ +# if IS_IN (libc) && defined SHARED + /* Check if Shadow Stack is enabled. */ + testl $(1 << 1), %fs:FEATURE_1_OFFSET + jz .Lskip_ssp +# endif + /* Get the current Shadow-Stack-Pointer and save it. */ + xorl %eax, %eax + rdsspq %rax + movq %rax, SHADOW_STACK_POINTER_OFFSET(%rdi) +# if IS_IN (libc) && defined SHARED +.Lskip_ssp: +# endif +#endif +#if IS_IN (rtld) + /* In ld.so we never save the signal mask. */ + xorl %eax, %eax + retq +#else + /* Make a tail call to __sigjmp_save; it takes the same args. */ + jmp __sigjmp_save +#endif +END (__sigsetjmp) +hidden_def (__sigsetjmp)