Received: by 2002:a05:6a10:1a4d:0:0:0:0 with SMTP id nk13csp622609pxb; Tue, 1 Feb 2022 07:10:51 -0800 (PST) X-Google-Smtp-Source: ABdhPJy7a52914RmcDE50xVZETHHbBZbIJnw1mp1HXNg4ZEsp09RQMgWkm+LTjkvtm1tQ+xPGMW7 X-Received: by 2002:aa7:dcd5:: with SMTP id w21mr26409720edu.97.1643728251572; Tue, 01 Feb 2022 07:10:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1643728251; cv=none; d=google.com; s=arc-20160816; b=qQ9YCeJNsplUVaOWmmwKsKMvVxe1CNvzIq8939NKEnSyzrtLc99EsztH22o1mBME3d fTnCsAizy40lt7rZkIRksyqYK6Tfnw0Cp/tnhk+wBPOku2HlCJaW8dYALRMU5kjNsFfg kP7FX7P7U+tmgWifgKWtNUMItRnfQuwMbxfWWqC/hiycSWWAv0SXD2Bu77egXQWi4aee /Qd3dC2FRfqzVZCSJgW0+CObLRg8V4qFQ7NvGFWC9bb34FoTnC6JkvrjJKTxmQN+EMWQ Dl2tHVjuiTLYUzsYZOcHu+VFx1UXiCdwj4gBzSBDvCpWIKRrop1PeOlYEUwpwUPhrAp7 7Zrw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:dkim-signature; bh=aGCl356KxSu6E2uOBLlfNdl87JZjKaWHHOfv3enY4tM=; b=ZDABbG6lMQ5kFpsVapBDZdYY11jNoDvAuUKbaYOjg3jyZJDLYfhhtZGeUePNi91EvC xiYNu5HxrdkZbo2AYREtyUE58xHWzGXo3GQtkXIRCmhL95zsMvr2D+SQtHqrqXRazaPG c6FEfiDVGfyHt4ATg4osxukCwqjIbRG0GXrfxTiZBP723JmtN1ebJ3GRoE4hloPw2cFh q5BR6Lob8D5dWqaseZ/2OIOSM3r1wMEDg46QO6zqelxNPvDJKdca6qXndL4SQJcpwAzs S4T35RZmsdrDbMF6d4Sd1rDDnwBXf269xqISTWkpOp4BKo/JumZND7GUxET6WgrriFDX QPsQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=ly7ijwrA; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id s1si11543116ejn.15.2022.02.01.07.10.25; Tue, 01 Feb 2022 07:10:51 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=ly7ijwrA; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356840AbiA3VZd (ORCPT + 99 others); Sun, 30 Jan 2022 16:25:33 -0500 Received: from mga07.intel.com ([134.134.136.100]:9048 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356510AbiA3VX7 (ORCPT ); Sun, 30 Jan 2022 16:23:59 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1643577839; x=1675113839; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=d0Xgzna4gIh3ZuI3ZOXqKNlQFX4CnUeeaybj1VMMDGA=; b=ly7ijwrAjPrRN4pl8Xd7lpDFNTFdkmWCdctWv4IHuw7q199RNiYcaaWS Nk5Y5aHixXbNYyhfTuwvQxtxoaOmMqW37Jme0UkD02cwg6Vg8gzrNKVP3 MFh68fEldB+J8dhdcQcEbSXyodu1fBdjBV4s53WPkzkSMcxTI8K7rTTFP MR9pin9PmbqBddSALYS2zkZkdTZxNBfCP6SQGPVH4zfUANdLOGOT1gERO xSvAWr2hgcRr5G3eFb8LCxltUBjn5OOalO2gXMUSHZVrXgGH2tFzFfWXr cddP8vaOPCWecVlTY2btSDhrgQy3QuXQNfSNXAUcmU997xSWx71CcYR6I g==; X-IronPort-AV: E=McAfee;i="6200,9189,10243"; a="310685826" X-IronPort-AV: E=Sophos;i="5.88,329,1635231600"; d="scan'208";a="310685826" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Jan 2022 13:22:10 -0800 X-IronPort-AV: E=Sophos;i="5.88,329,1635231600"; d="scan'208";a="536856972" Received: from avmallar-mobl1.amr.corp.intel.com (HELO rpedgeco-desk.amr.corp.intel.com) ([10.209.123.171]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Jan 2022 13:22:09 -0800 From: Rick Edgecombe To: x86@kernel.org, "H . Peter Anvin" , Thomas Gleixner , Ingo Molnar , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-mm@kvack.org, linux-arch@vger.kernel.org, linux-api@vger.kernel.org, Arnd Bergmann , Andy Lutomirski , Balbir Singh , Borislav Petkov , Cyrill Gorcunov , Dave Hansen , Eugene Syromiatnikov , Florian Weimer , "H . J . Lu" , Jann Horn , Jonathan Corbet , Kees Cook , Mike Kravetz , Nadav Amit , Oleg Nesterov , Pavel Machek , Peter Zijlstra , Randy Dunlap , "Ravi V . Shankar" , Dave Martin , Weijiang Yang , "Kirill A . Shutemov" , joao.moreira@intel.com, John Allen , kcc@google.com, eranian@google.com Cc: rick.p.edgecombe@intel.com, Yu-cheng Yu Subject: [PATCH 30/35] x86/cet/shstk: Handle signals for shadow stack Date: Sun, 30 Jan 2022 13:18:33 -0800 Message-Id: <20220130211838.8382-31-rick.p.edgecombe@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220130211838.8382-1-rick.p.edgecombe@intel.com> References: <20220130211838.8382-1-rick.p.edgecombe@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Yu-cheng Yu When a signal is handled normally the context is pushed to the stack before handling it. For shadow stacks, since the shadow stack only track's return addresses, there isn't any state that needs to be pushed. However, there are still a few things that need to be done. These things are userspace visible and which will be kernel ABI for shadow stacks. One is to make sure the restorer address is written to shadow stack, since the signal handler (if not changing ucontext) returns to the restorer, and the restorer calls sigreturn. So add the restorer on the shadow stack before handling the signal, so there is not a conflict when the signal handler returns to the restorer. The other thing to do is to place a restore token on the thread's shadow stack before handling the signal and check it during sigreturn. This is an extra layer of protection to hamper attackers calling sigreturn manually as in SROP-like attacks. So, when handling a signal push - a shadow stack restore token pointing to the current shadow stack address - the restorer address below the restore token. In sigreturn, verify the restore token and pop the shadow stack. Signed-off-by: Yu-cheng Yu Signed-off-by: Rick Edgecombe Cc: Andy Lutomirski Cc: Cyrill Gorcunov Cc: Florian Weimer Cc: H. Peter Anvin Cc: Kees Cook --- v1: - Use xsave helpers. - Expand commit log. Yu-cheng v27: - Eliminate saving shadow stack pointer to signal context. Yu-cheng v25: - Update commit log/comments for the sc_ext struct. - Use restorer address already calculated. - Change CONFIG_X86_CET to CONFIG_X86_SHADOW_STACK. - Change X86_FEATURE_CET to X86_FEATURE_SHSTK. - Eliminate writing to MSR_IA32_U_CET for shadow stack. - Change wrmsrl() to wrmsrl_safe() and handle error. arch/x86/ia32/ia32_signal.c | 25 ++++++++++++++++----- arch/x86/include/asm/cet.h | 4 ++++ arch/x86/kernel/shstk.c | 44 +++++++++++++++++++++++++++++++++++++ arch/x86/kernel/signal.c | 13 +++++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index c9c3859322fa..a8d038409d60 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -34,6 +34,7 @@ #include #include #include +#include static inline void reload_segments(struct sigcontext_32 *sc) { @@ -112,6 +113,10 @@ COMPAT_SYSCALL_DEFINE0(sigreturn) if (!ia32_restore_sigcontext(regs, &frame->sc)) goto badframe; + + if (restore_signal_shadow_stack()) + goto badframe; + return regs->ax; badframe: @@ -137,6 +142,9 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn) if (!ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; + if (restore_signal_shadow_stack()) + goto badframe; + if (compat_restore_altstack(&frame->uc.uc_stack)) goto badframe; @@ -261,6 +269,9 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, restorer = &frame->retcode; } + if (setup_signal_shadow_stack(1, restorer)) + return -EFAULT; + if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; @@ -318,6 +329,15 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, frame = get_sigframe(ksig, regs, sizeof(*frame), &fp); + if (ksig->ka.sa.sa_flags & SA_RESTORER) + restorer = ksig->ka.sa.sa_restorer; + else + restorer = current->mm->context.vdso + + vdso_image_32.sym___kernel_rt_sigreturn; + + if (setup_signal_shadow_stack(1, restorer)) + return -EFAULT; + if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; @@ -333,11 +353,6 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, unsafe_put_user(0, &frame->uc.uc_link, Efault); unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault); - if (ksig->ka.sa.sa_flags & SA_RESTORER) - restorer = ksig->ka.sa.sa_restorer; - else - restorer = current->mm->context.vdso + - vdso_image_32.sym___kernel_rt_sigreturn; unsafe_put_user(ptr_to_compat(restorer), &frame->pretcode, Efault); /* diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h index 6e8a7a807dcc..faff8dc86159 100644 --- a/arch/x86/include/asm/cet.h +++ b/arch/x86/include/asm/cet.h @@ -22,6 +22,8 @@ void reset_thread_shstk(void); int shstk_setup_rstor_token(bool proc32, unsigned long restorer, unsigned long *new_ssp); int shstk_check_rstor_token(bool proc32, unsigned long *new_ssp); +int setup_signal_shadow_stack(int proc32, void __user *restorer); +int restore_signal_shadow_stack(void); #else static inline void shstk_setup(void) {} static inline int shstk_alloc_thread_stack(struct task_struct *p, @@ -34,6 +36,8 @@ static inline int shstk_setup_rstor_token(bool proc32, unsigned long restorer, unsigned long *new_ssp) { return 0; } static inline int shstk_check_rstor_token(bool proc32, unsigned long *new_ssp) { return 0; } +static inline int setup_signal_shadow_stack(int proc32, void __user *restorer) { return 0; } +static inline int restore_signal_shadow_stack(void) { return 0; } #endif /* CONFIG_X86_SHADOW_STACK */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c index e0caab50ca77..682d85a63a1d 100644 --- a/arch/x86/kernel/shstk.c +++ b/arch/x86/kernel/shstk.c @@ -335,3 +335,47 @@ int shstk_check_rstor_token(bool proc32, unsigned long *new_ssp) return 0; } + +int setup_signal_shadow_stack(int proc32, void __user *restorer) +{ + struct thread_shstk *shstk = ¤t->thread.shstk; + unsigned long new_ssp; + void *xstate; + int err; + + if (!cpu_feature_enabled(X86_FEATURE_SHSTK) || !shstk->size) + return 0; + + err = shstk_setup_rstor_token(proc32, (unsigned long)restorer, + &new_ssp); + if (err) + return err; + + xstate = start_update_xsave_msrs(XFEATURE_CET_USER); + err = xsave_wrmsrl(xstate, MSR_IA32_PL3_SSP, new_ssp); + end_update_xsave_msrs(); + + return err; +} + +int restore_signal_shadow_stack(void) +{ + struct thread_shstk *shstk = ¤t->thread.shstk; + void *xstate; + int proc32 = in_ia32_syscall(); + unsigned long new_ssp; + int err; + + if (!cpu_feature_enabled(X86_FEATURE_SHSTK) || !shstk->size) + return 0; + + err = shstk_check_rstor_token(proc32, &new_ssp); + if (err) + return err; + + xstate = start_update_xsave_msrs(XFEATURE_CET_USER); + err = xsave_wrmsrl(xstate, MSR_IA32_PL3_SSP, new_ssp); + end_update_xsave_msrs(); + + return err; +} diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index ec71e06ae364..e6202fc2a56c 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -48,6 +48,7 @@ #include #include #include +#include #ifdef CONFIG_X86_64 /* @@ -471,6 +472,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp); uc_flags = frame_uc_flags(regs); + if (setup_signal_shadow_stack(0, ksig->ka.sa.sa_restorer)) + return -EFAULT; + if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; @@ -576,6 +580,9 @@ static int x32_setup_rt_frame(struct ksignal *ksig, uc_flags = frame_uc_flags(regs); + if (setup_signal_shadow_stack(0, ksig->ka.sa.sa_restorer)) + return -EFAULT; + if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; @@ -674,6 +681,9 @@ SYSCALL_DEFINE0(rt_sigreturn) if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags)) goto badframe; + if (restore_signal_shadow_stack()) + goto badframe; + if (restore_altstack(&frame->uc.uc_stack)) goto badframe; @@ -991,6 +1001,9 @@ COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn) if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags)) goto badframe; + if (restore_signal_shadow_stack()) + goto badframe; + if (compat_restore_altstack(&frame->uc.uc_stack)) goto badframe; -- 2.17.1