From patchwork Tue Jun 13 00:10:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Edgecombe, Rick P" X-Patchwork-Id: 13277746 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id A61B5C7EE43 for ; Tue, 13 Jun 2023 00:13:24 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id EAC128E0020; Mon, 12 Jun 2023 20:12:38 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id E36668E000B; Mon, 12 Jun 2023 20:12:38 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id BA1878E0021; Mon, 12 Jun 2023 20:12:38 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id 9AA6E8E0020 for ; Mon, 12 Jun 2023 20:12:38 -0400 (EDT) Received: from smtpin10.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id 6A26A80378 for ; Tue, 13 Jun 2023 00:12:38 +0000 (UTC) X-FDA: 80895798396.10.760E2CD Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by imf01.hostedemail.com (Postfix) with ESMTP id 3AD4D4000B for ; Tue, 13 Jun 2023 00:12:36 +0000 (UTC) Authentication-Results: imf01.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=QOnyf2BN; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf01.hostedemail.com: domain of rick.p.edgecombe@intel.com designates 134.134.136.65 as permitted sender) smtp.mailfrom=rick.p.edgecombe@intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1686615156; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=MgDcxUbk8bavQieeuDWIimstnW9ktFErCUXNtfQmk0E=; b=hVnZ913vtSA9+uAAfMFrUzbPvYStV7nJ0Auk6uV3u4M+OM9KUzKwfLEBT7QNXH4X0MnIox +uy7nAzlHrgpO5cgCAhFcw5TP5Jz3e5CsDuR6HY/91l8uLuh9RvcvlU5RR3sFdNAayoRPg bmI5zEyeGnQZ57ww1K0y8j/32EDixKE= ARC-Authentication-Results: i=1; imf01.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=QOnyf2BN; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf01.hostedemail.com: domain of rick.p.edgecombe@intel.com designates 134.134.136.65 as permitted sender) smtp.mailfrom=rick.p.edgecombe@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1686615156; a=rsa-sha256; cv=none; b=dGP3qQReJgxwnIjqP4WYsF0VjfbYwnH7Md9HIp//oH1O7qfXyKZVxbxggx2N8PJQ99PGa3 /MzKj+FoXX9SF2IQbIPwQ/ENUj+lz8iFC5dk6cXh1ZZG7ogvgTeUNx2g+U0r0gh6GsJuNB 3I+haaIZiqZ3wsotJzHQckEdW16xNFc= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1686615156; x=1718151156; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5PTalCu64urUNwCF3tCp/oZ88l0SJTltpYFQdwbjc9Y=; b=QOnyf2BNsWy7PSiwD8DoBlNo/viIb6zVJfGIVeY9bUrQ1jM3IpEGMHzH dW+c25OaFv03DWA+7J5LYYYHcQ2eOwxT2muexyiA7NB5nfWRNG51UGerP k/jNCiZntqlIUc+GjhlINnupYargeKBfXn4AJ0S9T0fluR39V/znI4rBN phSbasdDOzZyHIj14zJJRnQ9ZeNT0FWI48IYAfegY4a42zgl8Uly76AP0 iAKUJKR7rNl97Su4iMgZg63WUgDAtKJIKm+dF1IgHr34rlsnD2oJsLAW4 iLSbS87oM1YHVHYBgZY/xMg0o4vF3NThI4WbpvtZIsIV0JIar6Q5TKXBC A==; X-IronPort-AV: E=McAfee;i="6600,9927,10739"; a="361557398" X-IronPort-AV: E=Sophos;i="6.00,238,1681196400"; d="scan'208";a="361557398" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Jun 2023 17:12:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10739"; a="835671109" X-IronPort-AV: E=Sophos;i="6.00,238,1681196400"; d="scan'208";a="835671109" Received: from almeisch-mobl1.amr.corp.intel.com (HELO rpedgeco-desk4.amr.corp.intel.com) ([10.209.42.242]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Jun 2023 17:12:34 -0700 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 , Weijiang Yang , "Kirill A . Shutemov" , John Allen , kcc@google.com, eranian@google.com, rppt@kernel.org, jamorris@linux.microsoft.com, dethoma@microsoft.com, akpm@linux-foundation.org, Andrew.Cooper3@citrix.com, christina.schimpe@intel.com, david@redhat.com, debug@rivosinc.com, szabolcs.nagy@arm.com, torvalds@linux-foundation.org, broonie@kernel.org Cc: rick.p.edgecombe@intel.com, Yu-cheng Yu , Pengfei Xu Subject: [PATCH v9 31/42] x86/shstk: Handle signals for shadow stack Date: Mon, 12 Jun 2023 17:10:57 -0700 Message-Id: <20230613001108.3040476-32-rick.p.edgecombe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230613001108.3040476-1-rick.p.edgecombe@intel.com> References: <20230613001108.3040476-1-rick.p.edgecombe@intel.com> MIME-Version: 1.0 X-Rspamd-Server: rspam09 X-Rspamd-Queue-Id: 3AD4D4000B X-Stat-Signature: b68nrdc3p6ifntj1nyp3fh46qxguh4ti X-Rspam-User: X-HE-Tag: 1686615156-281505 X-HE-Meta: U2FsdGVkX1996bjxlKff084mpNjdlOiiMLERQPZk0oDjUYin/LpHwoR9rHrFc4HMwSOBGq8bnuIuN/RfaSGsL7XYI7Qb3uPReBFgQ0TCJIJADOFW94FeJZUwp3FhgroWeYVbXu0mAtaBqnoNdADN0NUuC4sN68d6/XY6miQZ6Iq5ul8bfT2iUXYudcZGDIo3jEET7CvTU6DrDGc5ZWGhl4Wv9nmR6zRF+pYzjZ4JDawggmc0Z+A0GrnY9KBXZ43TxbpsKa4/6ffTPYZvjA/j2SSJCD8iI6W8sXIER6xuvubm/E76wK4P9TFjrDwNQbaJhJkALhGNuYN6Z+EeFFw2nFpRybarGXM4d1XVa/TH3sncjwWbeMc07aDt5RxsU6EvHAF6v4jQUY01Tg51E56Plt0GRTr6UKVIpxIjZ0JxmlQu3vEInO3YNw3JjsHQTGE/FLKv0iybn4rOQGUoZDMwFd/4VyAazCQ9mbGUc5PR4z/nsn2N8po0VySdnu0GFnoYpg+W78s1X0JmgMhXW8IacLptPliVXyGl1naB9gsgm0Qn6wbtfoXQyWQeMc7rUpNiHZFhTUAwFPbGtQPphoMIs6Cnfu/+AY7mDRHPyXLn+g90oFvvUqp2ClX9Dt2BBLgoacqhzXF/UufxaHlGg5nf6em+MNF46147JK5x2fK+rrrRyZsW/Zhem66V47KJEEwz3mw/lcK7KbyO42qAYRBIaPD87ERPr+0TNTLw47ecg474w2B6O0n0pyHSPR+ZusYh1FQAp4zgyp4x80mE1sF0jNKdE9TIIZ4T1hIaUiD4z3Usv5OibKhXdebYfFsHoIW1eI52alXHpsdy0CZMLrjhwgR3MR5aTilEOtyRXodXPKYvbHvfNNbOKOf4Rr3Kj88NeefVrsXQm888/yQ3dCIAE2OmEWLp9vlm3fb137fzFM9y0xDPw6s4LD8x9ooZz9Q+4sFNAnLiVeBVLOy3i7U x3RqeU35 LflVmkQNDpPLn1XAs0IRM4T01T3tbwFqBqHLlVCFmxXm6W+Q7bOVF0YLoA2pIu4MAmIhGO9GjUb3cyNA9ZcaU89ZnYTn18LFCya4/cHU957cihGypajetyRyl3yp7VZI54nwximlQ0KLACB4s+Hb3kdZztEUbzHQLi6Vr2m1c5o0sJJ4kZWXF8HjEBBiC2oC5o4/H6+eFzQlYd3aSUK7ZIqBKj4F2DmpWjLbLqbQFBZTXv+h8PRxQH+MxZKFZTqVmbMBzDR9awvHeeBmeJjyDS6jDvOV7YI2Gm5TJBlzd6toiwdVr8XqHd071VGM8OkA1rzqZ5QDd7umqpZ/HyHOsCXRPRwsXob+BI7VBX37SBUceO7MPKXDBCQ0unA== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: When a signal is handled, the context is pushed to the stack before handling it. For shadow stacks, since the shadow stack only tracks 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 visible to userspace 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 some type of checkable 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. For this token the shadow stack data format defined earlier can be used. Have the data pushed be the previous SSP. In the future the sigreturn might want to return back to a different stack. Storing the SSP (instead of a restore offset or something) allows for future functionality that may want to restore to a different stack. So, when handling a signal push - the SSP pointing in the shadow stack data format - the restorer address below the restore token. In sigreturn, verify SSP is stored in the data format and pop the shadow stack. Co-developed-by: Yu-cheng Yu Signed-off-by: Yu-cheng Yu Signed-off-by: Rick Edgecombe Reviewed-by: Borislav Petkov (AMD) Reviewed-by: Kees Cook Acked-by: Mike Rapoport (IBM) Tested-by: Pengfei Xu Tested-by: John Allen Tested-by: Kees Cook --- arch/x86/include/asm/shstk.h | 5 ++ arch/x86/kernel/shstk.c | 95 ++++++++++++++++++++++++++++++++++++ arch/x86/kernel/signal.c | 1 + arch/x86/kernel/signal_64.c | 6 +++ 4 files changed, 107 insertions(+) diff --git a/arch/x86/include/asm/shstk.h b/arch/x86/include/asm/shstk.h index d4a5c7b10cb5..ecb23a8ca47d 100644 --- a/arch/x86/include/asm/shstk.h +++ b/arch/x86/include/asm/shstk.h @@ -6,6 +6,7 @@ #include struct task_struct; +struct ksignal; #ifdef CONFIG_X86_USER_SHADOW_STACK struct thread_shstk { @@ -18,6 +19,8 @@ void reset_thread_features(void); unsigned long shstk_alloc_thread_stack(struct task_struct *p, unsigned long clone_flags, unsigned long stack_size); void shstk_free(struct task_struct *p); +int setup_signal_shadow_stack(struct ksignal *ksig); +int restore_signal_shadow_stack(void); #else static inline long shstk_prctl(struct task_struct *task, int option, unsigned long arg2) { return -EINVAL; } @@ -26,6 +29,8 @@ static inline unsigned long shstk_alloc_thread_stack(struct task_struct *p, unsigned long clone_flags, unsigned long stack_size) { return 0; } static inline void shstk_free(struct task_struct *p) {} +static inline int setup_signal_shadow_stack(struct ksignal *ksig) { return 0; } +static inline int restore_signal_shadow_stack(void) { return 0; } #endif /* CONFIG_X86_USER_SHADOW_STACK */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c index e22928c63ffc..f02e8ea4f1b5 100644 --- a/arch/x86/kernel/shstk.c +++ b/arch/x86/kernel/shstk.c @@ -232,6 +232,101 @@ static int get_shstk_data(unsigned long *data, unsigned long __user *addr) return 0; } +static int shstk_push_sigframe(unsigned long *ssp) +{ + unsigned long target_ssp = *ssp; + + /* Token must be aligned */ + if (!IS_ALIGNED(target_ssp, 8)) + return -EINVAL; + + *ssp -= SS_FRAME_SIZE; + if (put_shstk_data((void *__user)*ssp, target_ssp)) + return -EFAULT; + + return 0; +} + +static int shstk_pop_sigframe(unsigned long *ssp) +{ + unsigned long token_addr; + int err; + + err = get_shstk_data(&token_addr, (unsigned long __user *)*ssp); + if (unlikely(err)) + return err; + + /* Restore SSP aligned? */ + if (unlikely(!IS_ALIGNED(token_addr, 8))) + return -EINVAL; + + /* SSP in userspace? */ + if (unlikely(token_addr >= TASK_SIZE_MAX)) + return -EINVAL; + + *ssp = token_addr; + + return 0; +} + +int setup_signal_shadow_stack(struct ksignal *ksig) +{ + void __user *restorer = ksig->ka.sa.sa_restorer; + unsigned long ssp; + int err; + + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK) || + !features_enabled(ARCH_SHSTK_SHSTK)) + return 0; + + if (!restorer) + return -EINVAL; + + ssp = get_user_shstk_addr(); + if (unlikely(!ssp)) + return -EINVAL; + + err = shstk_push_sigframe(&ssp); + if (unlikely(err)) + return err; + + /* Push restorer address */ + ssp -= SS_FRAME_SIZE; + err = write_user_shstk_64((u64 __user *)ssp, (u64)restorer); + if (unlikely(err)) + return -EFAULT; + + fpregs_lock_and_load(); + wrmsrl(MSR_IA32_PL3_SSP, ssp); + fpregs_unlock(); + + return 0; +} + +int restore_signal_shadow_stack(void) +{ + unsigned long ssp; + int err; + + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK) || + !features_enabled(ARCH_SHSTK_SHSTK)) + return 0; + + ssp = get_user_shstk_addr(); + if (unlikely(!ssp)) + return -EINVAL; + + err = shstk_pop_sigframe(&ssp); + if (unlikely(err)) + return err; + + fpregs_lock_and_load(); + wrmsrl(MSR_IA32_PL3_SSP, ssp); + fpregs_unlock(); + + return 0; +} + void shstk_free(struct task_struct *tsk) { struct thread_shstk *shstk = &tsk->thread.shstk; diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 004cb30b7419..356253e85ce9 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -40,6 +40,7 @@ #include #include #include +#include static inline int is_ia32_compat_frame(struct ksignal *ksig) { diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 0e808c72bf7e..cacf2ede6217 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@ -175,6 +175,9 @@ int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) frame = get_sigframe(ksig, regs, sizeof(struct rt_sigframe), &fp); uc_flags = frame_uc_flags(regs); + if (setup_signal_shadow_stack(ksig)) + return -EFAULT; + if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; @@ -260,6 +263,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;