From patchwork Wed Aug 2 22:19:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: tip-bot2 for Thomas Gleixner X-Patchwork-Id: 130228 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9f41:0:b0:3e4:2afc:c1 with SMTP id v1csp807631vqx; Wed, 2 Aug 2023 17:08:37 -0700 (PDT) X-Google-Smtp-Source: APBJJlG8OMQ+AZluSG53NbKPO/OYCar7rV49tHloJPnC93Lh86WiWdLpc/82vV1hZO6JIQZX2EaC X-Received: by 2002:a05:651c:2c6:b0:2b9:6610:d7ca with SMTP id f6-20020a05651c02c600b002b96610d7camr7703542ljo.5.1691021317389; Wed, 02 Aug 2023 17:08:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1691021317; cv=none; d=google.com; s=arc-20160816; b=cN7RtnexyfWqEacsFFYxNcV9dtoQpvbiS1u9YRY0DvgQ7qu3vb7tRJ4SxEse1lZv69 lxMz/Gc4coZ+x7wPfmLEl2OiRxa3e81YHYzVxAnGj1GKmxi0jjWahjrVhHyGIVsI0Daz rp+0RhIEwYN3SMHfIFdt5Vcd+eDqG/JHpdPMabHbjVxBoUYQL/UfqDHbfeQPJl5W1ena MLmHSxo0fK6deex8+ECCTcbLdZngDC2TLRD46gvXiQFpNI5UMyto6e4t1e9HxBzu+7Ru ih7OKAa5Gw3hK7Vyjy5Kv7wiuS5YSSIokJXrFYQMKVDvM2lIcZ61/XXUohk01gwbipO/ VnXw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:robot-unsubscribe :robot-id:message-id:mime-version:cc:subject:to:reply-to:sender:from :dkim-signature:dkim-signature:date; bh=gcyn36Jv3HtGUnwQSizKMwQBNb1jMXnbeMRFzDKvjBo=; fh=cYKsLYKlfL5GLDpOt1a9DaF93PQ8azQhO0iBCt+veh0=; b=z23Kdn3TES+H8e12n/iYvXMr/V8PpVdRmIRHBMyx3gGQeWz6XcEplFN5L/MznO//vD NIuIBp8kPAFT8G6fXzpUrcfreVI3q8ul+8gArVGqhCMcLaslLQqGPwYgXOTmd3nTqs3s B+RyL1+h8gEds2mCqXdg81svpRYUFlCv0jLnvu88BRc0b3nEBwp4Ae0LiZmIYiSYSaSH bLuS1hvaxPsT9whZaYy+Q175AZu27bcOlzaazmJwMdOudoFxN3yLsp4rPdliJ7/v6AFk gG3Ql794KTIPY7e2u/ql4iMTnIjWeEmMSkrLU++1EZwfAM0Gx3R7oEXQD2NvVKwQlk+S KcLA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=R6BsfNuY; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id va16-20020a17090711d000b009874842217bsi11481751ejb.441.2023.08.02.17.08.13; Wed, 02 Aug 2023 17:08:37 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=R6BsfNuY; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234029AbjHBWUp (ORCPT + 99 others); Wed, 2 Aug 2023 18:20:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233902AbjHBWTz (ORCPT ); Wed, 2 Aug 2023 18:19:55 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AC8BC2D68; Wed, 2 Aug 2023 15:19:37 -0700 (PDT) Date: Wed, 02 Aug 2023 22:19:35 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1691014776; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gcyn36Jv3HtGUnwQSizKMwQBNb1jMXnbeMRFzDKvjBo=; b=R6BsfNuYzJt2kvvcTkeP3m1c73bq/38RqaQ4BT3Nt/PCsEfKKFUuw7i2TWWF/A/eL13N/k RcIJDafLG4yAtOutumjL/osRy3chncGnTXRLSZRTYtp+djCWc3r5PzHiZJdHTExurnFnII v+5eYPAxBrNCWkhZEbvsj2UZqBUjUrbGiCtI9gSs1JbDTrgf3h/v/pVxcowlgEN/qGX2EP 2po5JIoo9c50R38yK9CbPpsnV7fah32WpgqjFdagQ77UDAhxJurwl7RrVxBBWycx1eZpZt uHUpu1n3mrSMU+4qdAQK65cPibe5wUVySWKldXtcAOe9DLmkRzjYplsJ6U2XaA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1691014776; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gcyn36Jv3HtGUnwQSizKMwQBNb1jMXnbeMRFzDKvjBo=; b=g8rnXANsc0TqrXQZmd8vZaaHcBqXm2+NR00fd/tpojRmwuf6JaWktVPIU1wmJmT7ywR/pb tC/iIHOaReufZlAA== From: "tip-bot2 for Rick Edgecombe" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: x86/shstk] x86/shstk: Add user-mode shadow stack support Cc: "Yu-cheng Yu" , Rick Edgecombe , Dave Hansen , "Borislav Petkov (AMD)" , Kees Cook , "Mike Rapoport (IBM)" , Pengfei Xu , John Allen , x86@kernel.org, linux-kernel@vger.kernel.org MIME-Version: 1.0 Message-ID: <169101477502.28540.12081103518877160423.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1773164369071364399 X-GMAIL-MSGID: 1773164369071364399 The following commit has been merged into the x86/shstk branch of tip: Commit-ID: 2d39a6add422ac78254927ec2194838c33ae4fb2 Gitweb: https://git.kernel.org/tip/2d39a6add422ac78254927ec2194838c33ae4fb2 Author: Rick Edgecombe AuthorDate: Mon, 12 Jun 2023 17:10:54 -07:00 Committer: Dave Hansen CommitterDate: Wed, 02 Aug 2023 15:01:50 -07:00 x86/shstk: Add user-mode shadow stack support Introduce basic shadow stack enabling/disabling/allocation routines. A task's shadow stack is allocated from memory with VM_SHADOW_STACK flag and has a fixed size of min(RLIMIT_STACK, 4GB). Keep the task's shadow stack address and size in thread_struct. This will be copied when cloning new threads, but needs to be cleared during exec, so add a function to do this. 32 bit shadow stack is not expected to have many users and it will complicate the signal implementation. So do not support IA32 emulation or x32. Co-developed-by: Yu-cheng Yu Signed-off-by: Yu-cheng Yu Signed-off-by: Rick Edgecombe Signed-off-by: Dave Hansen 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 Link: https://lore.kernel.org/all/20230613001108.3040476-29-rick.p.edgecombe%40intel.com --- arch/x86/include/asm/processor.h | 2 +- arch/x86/include/asm/shstk.h | 7 +- arch/x86/include/uapi/asm/prctl.h | 3 +- arch/x86/kernel/shstk.c | 145 +++++++++++++++++++++++++++++- 4 files changed, 157 insertions(+) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 4e35f40..b216ac8 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -479,6 +479,8 @@ struct thread_struct { #ifdef CONFIG_X86_USER_SHADOW_STACK unsigned long features; unsigned long features_locked; + + struct thread_shstk shstk; #endif /* Floating point and extended processor state */ diff --git a/arch/x86/include/asm/shstk.h b/arch/x86/include/asm/shstk.h index ec75380..2b1f7c9 100644 --- a/arch/x86/include/asm/shstk.h +++ b/arch/x86/include/asm/shstk.h @@ -8,12 +8,19 @@ struct task_struct; #ifdef CONFIG_X86_USER_SHADOW_STACK +struct thread_shstk { + u64 base; + u64 size; +}; + long shstk_prctl(struct task_struct *task, int option, unsigned long features); void reset_thread_features(void); +void shstk_free(struct task_struct *p); #else static inline long shstk_prctl(struct task_struct *task, int option, unsigned long arg2) { return -EINVAL; } static inline void reset_thread_features(void) {} +static inline void shstk_free(struct task_struct *p) {} #endif /* CONFIG_X86_USER_SHADOW_STACK */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h index 1cd44ec..6a8e0e1 100644 --- a/arch/x86/include/uapi/asm/prctl.h +++ b/arch/x86/include/uapi/asm/prctl.h @@ -34,4 +34,7 @@ #define ARCH_SHSTK_DISABLE 0x5002 #define ARCH_SHSTK_LOCK 0x5003 +/* ARCH_SHSTK_ features bits */ +#define ARCH_SHSTK_SHSTK (1ULL << 0) + #endif /* _ASM_X86_PRCTL_H */ diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c index 41ed655..3cb8522 100644 --- a/arch/x86/kernel/shstk.c +++ b/arch/x86/kernel/shstk.c @@ -8,14 +8,159 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +static bool features_enabled(unsigned long features) +{ + return current->thread.features & features; +} + +static void features_set(unsigned long features) +{ + current->thread.features |= features; +} + +static void features_clr(unsigned long features) +{ + current->thread.features &= ~features; +} + +static unsigned long alloc_shstk(unsigned long size) +{ + int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_ABOVE4G; + struct mm_struct *mm = current->mm; + unsigned long addr, unused; + + mmap_write_lock(mm); + addr = do_mmap(NULL, addr, size, PROT_READ, flags, + VM_SHADOW_STACK | VM_WRITE, 0, &unused, NULL); + + mmap_write_unlock(mm); + + return addr; +} + +static unsigned long adjust_shstk_size(unsigned long size) +{ + if (size) + return PAGE_ALIGN(size); + + return PAGE_ALIGN(min_t(unsigned long long, rlimit(RLIMIT_STACK), SZ_4G)); +} + +static void unmap_shadow_stack(u64 base, u64 size) +{ + while (1) { + int r; + + r = vm_munmap(base, size); + + /* + * vm_munmap() returns -EINTR when mmap_lock is held by + * something else, and that lock should not be held for a + * long time. Retry it for the case. + */ + if (r == -EINTR) { + cond_resched(); + continue; + } + + /* + * For all other types of vm_munmap() failure, either the + * system is out of memory or there is bug. + */ + WARN_ON_ONCE(r); + break; + } +} + +static int shstk_setup(void) +{ + struct thread_shstk *shstk = ¤t->thread.shstk; + unsigned long addr, size; + + /* Already enabled */ + if (features_enabled(ARCH_SHSTK_SHSTK)) + return 0; + + /* Also not supported for 32 bit and x32 */ + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK) || in_32bit_syscall()) + return -EOPNOTSUPP; + + size = adjust_shstk_size(0); + addr = alloc_shstk(size); + if (IS_ERR_VALUE(addr)) + return PTR_ERR((void *)addr); + + fpregs_lock_and_load(); + wrmsrl(MSR_IA32_PL3_SSP, addr + size); + wrmsrl(MSR_IA32_U_CET, CET_SHSTK_EN); + fpregs_unlock(); + + shstk->base = addr; + shstk->size = size; + features_set(ARCH_SHSTK_SHSTK); + + return 0; +} + void reset_thread_features(void) { + memset(¤t->thread.shstk, 0, sizeof(struct thread_shstk)); current->thread.features = 0; current->thread.features_locked = 0; } +void shstk_free(struct task_struct *tsk) +{ + struct thread_shstk *shstk = &tsk->thread.shstk; + + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK) || + !features_enabled(ARCH_SHSTK_SHSTK)) + return; + + if (!tsk->mm) + return; + + unmap_shadow_stack(shstk->base, shstk->size); +} + +static int shstk_disable(void) +{ + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK)) + return -EOPNOTSUPP; + + /* Already disabled? */ + if (!features_enabled(ARCH_SHSTK_SHSTK)) + return 0; + + fpregs_lock_and_load(); + /* Disable WRSS too when disabling shadow stack */ + wrmsrl(MSR_IA32_U_CET, 0); + wrmsrl(MSR_IA32_PL3_SSP, 0); + fpregs_unlock(); + + shstk_free(current); + features_clr(ARCH_SHSTK_SHSTK); + + return 0; +} + long shstk_prctl(struct task_struct *task, int option, unsigned long features) { if (option == ARCH_SHSTK_LOCK) {