From patchwork Mon Feb 27 22:29:55 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: 13154270 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 E0288C88CB2 for ; Mon, 27 Feb 2023 22:32:34 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id CDAD46B00AB; Mon, 27 Feb 2023 17:32:03 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id B78366B00AD; Mon, 27 Feb 2023 17:32:03 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 9A2B76B00AE; Mon, 27 Feb 2023 17:32:03 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 884086B00AB for ; Mon, 27 Feb 2023 17:32:03 -0500 (EST) Received: from smtpin14.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 4D8DB40A7F for ; Mon, 27 Feb 2023 22:32:03 +0000 (UTC) X-FDA: 80514520926.14.47801E0 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by imf28.hostedemail.com (Postfix) with ESMTP id 54851C0010 for ; Mon, 27 Feb 2023 22:32:01 +0000 (UTC) Authentication-Results: imf28.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=ImIeiC4n; spf=pass (imf28.hostedemail.com: domain of rick.p.edgecombe@intel.com designates 192.55.52.136 as permitted sender) smtp.mailfrom=rick.p.edgecombe@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1677537121; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:in-reply-to: references:references:dkim-signature; bh=bud3WTrvZ04cWHpJ8882/Hx0ishqCggJIVkuvRwOAFs=; b=RXZPqfOguIX9aTnV/UNHcT/QJ6IOo1ntSM5q/V/gZT+KznAIGsIVvp4objpwEnsKSHjSd/ mGu8roUBWt0nTS1AhnnZ/mNTwO/hxQptmfS/SCGmibjss8QSAS89MKgirVZPxgMzv3yE+K lidjqTN0C34/BgCM6RPgeqS0UacLda4= ARC-Authentication-Results: i=1; imf28.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=ImIeiC4n; spf=pass (imf28.hostedemail.com: domain of rick.p.edgecombe@intel.com designates 192.55.52.136 as permitted sender) smtp.mailfrom=rick.p.edgecombe@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1677537121; a=rsa-sha256; cv=none; b=vLXt9zfYRCK0R5VRyMrZBgT4rZ4+vHuLdmUBKSOSMRrAkzetoEEF9YZsYhO2A4GfI6uTnd iEMVos7EK2RKMZT//1dLjw4DflrKEkMGRz1TRPRVutXnmigJ/jnsPdZQ30O2irZGqxpwwV bzvIcUwu7uJU7tWBzRT7+v3inXaJCCk= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1677537121; x=1709073121; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=UFVg3sIbuffnHjOtlNoaz9ZH+gYHjqQgnqMZvI5Wi8Y=; b=ImIeiC4nygVpzWj3ygGYlyJV6wivDkgHbD3B4p2RPHCRMRqeSZ3KHa9f pCKLckoQ8BA96Y2Pxh3At/7VyptjoTa2tC741Xd1lvni94c4Yh0+7OmRS ZSYwun1kJMhD4neR8p28iZvK0mhSXPwpx4aB03hLuhuaE94w7AynM5IWp zxy1l7s7qzmi8M3aImIfny5DRc96HwyNpCBpLyXAxZviVJaDXlr1TRF6T okv1Q7pemLmnyFO2/wnZQztrw+VmMENp+9WuT6VNTMLvGMcd0AfB3aigO Yv42XuVyRiUYvk+AhAzTvJJOdym6vgKtivd2JAKcW5SlijBaoAZGUccSr A==; X-IronPort-AV: E=McAfee;i="6500,9779,10634"; a="313657958" X-IronPort-AV: E=Sophos;i="5.98,220,1673942400"; d="scan'208";a="313657958" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Feb 2023 14:31:36 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10634"; a="848024813" X-IronPort-AV: E=Sophos;i="5.98,220,1673942400"; d="scan'208";a="848024813" Received: from leonqu-mobl1.amr.corp.intel.com (HELO rpedgeco-desk.amr.corp.intel.com) ([10.209.72.19]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Feb 2023 14:31:36 -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 , 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 Cc: rick.p.edgecombe@intel.com, Yu-cheng Yu Subject: [PATCH v7 39/41] x86: Add PTRACE interface for shadow stack Date: Mon, 27 Feb 2023 14:29:55 -0800 Message-Id: <20230227222957.24501-40-rick.p.edgecombe@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230227222957.24501-1-rick.p.edgecombe@intel.com> References: <20230227222957.24501-1-rick.p.edgecombe@intel.com> X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 54851C0010 X-Stat-Signature: f3bi1rcdyezgwfhkzfpw57yuwqjdm8ts X-Rspam-User: X-HE-Tag: 1677537121-148421 X-HE-Meta: U2FsdGVkX18xGDmOkS4nfkxOcRZHsupfnkL+XdWj6TyjiaaroUbcjZPJbqAOFliABnQZi3xYtPk/UuWEM4riM4Sr24WatwyvZWUMcVHnvMg/NINOwoppdjEKeY27EnAt6Mj53Mo65tql7rXtQX+uBEo76pquW0MyDvf3U39Z1JxwiU7TUkKHbb1IlPQRsWhU7mkEuFz4C0bZa2x92+HTvjl9iTjeOIFbO6h9XEV30w0hgl/Ys6CX9H47e2J3jhtAl8CGYnjSXRY4931viAqhR5nUY9qQG85HorDZrS1gxY2VtgS1Gcy8sJ2KLKTqmJ7zRQgPUMa1A/M5oFhKWrmwMDo2UL54v/Dh166v3tI9duZr03CnXvxVYohF/Wvca8OVUwJorSw7Af1gNzRIWFLCez5pB1vNj8rKN6mPQJNeD0ScFS3//i6LKUNLdrlklwnciHFL7YxTkcux8p7u4Bi/zSvkJk4Hc4MSduT2tvKU4AfIr1jaT36dXoa+x1MI47+BZVgzBKW21ELzsDrqRQFxq/PpYaHpJ3La5hiYvG/on1KE99MehvwErthGqiIIeVWhrCZsRz8tdUsabE1FuHrDPyBf5aAPJXNGRqVljgmDwtLP88e3ewZnzPQks562M/TGmuXAVzXGIXtnYsQOMfxdoZOSfDPe+d6mTSvnoWyEJmQqFozySxtZWgdWtYATaNjjEOZ2tZTXgfLpEMHvglXvUeRtfAX5UA+P7n8kg+ZUY/agoTqVCjLnZ7bdxUdzcjGQ+rYU5kNouN8FJlQitiR8oWNpHwLwYQN9dd/KwA654Nhiq5Fj2UQjbndCEC1xRTVHboibeNSIY48mYctlOOSTl9ik2JVS/qTGBilRmG9GsLD1diu4qJKJt0j5Waz7oUDaaBhL5/s8J+m35rDVnUFl6SmuHl1o2r1Dz4935bSDUxMxJmKgynHob0ZwwKbzKYPyYlj/unaXyvVE0xO99ks n49tcd/0 uyrkdc4oS52e01wsyYu6cH0zMssYkxsJUOLdaA7BbwMoHXi8OTKE8Nqv/Hum15y1qduS9KIw2mDysNNi9BoLymKs54Cd8gLG5/FcMFaVD9IEXqKrW7h5driSYPI9BbckDNtYdvk5656VrATbYoqpygWZS3H88Uq6OnNs1QA5nnW6yKE/E69I9ymzi1JXkcJ66/l/VC6ES9ywqBdN/miczI2n7efolv/C1Ho/8OcyTyAutt2nhRZyExCHHChL/tZH2Ez4fosf6H2gokqHFPtth9fTpaEO0ef5yZSwYMLoAQDX1jaIkD0FDzlivO64zpLNAkw4bYqRWf7wksZrFlyCKVexgVLVnZ6ioL4n+ 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: From: Yu-cheng Yu Some applications (like GDB) would like to tweak shadow stack state via ptrace. This allows for existing functionality to continue to work for seized shadow stack applications. Provide an regset interface for manipulating the shadow stack pointer (SSP). There is already ptrace functionality for accessing xstate, but this does not include supervisor xfeatures. So there is not a completely clear place for where to put the shadow stack state. Adding it to the user xfeatures regset would complicate that code, as it currently shares logic with signals which should not have supervisor features. Don't add a general supervisor xfeature regset like the user one, because it is better to maintain flexibility for other supervisor xfeatures to define their own interface. For example, an xfeature may decide not to expose all of it's state to userspace, as is actually the case for shadow stack ptrace functionality. A lot of enum values remain to be used, so just put it in dedicated shadow stack regset. The only downside to not having a generic supervisor xfeature regset, is that apps need to be enlightened of any new supervisor xfeature exposed this way (i.e. they can't try to have generic save/restore logic). But maybe that is a good thing, because they have to think through each new xfeature instead of encountering issues when new a new supervisor xfeature was added. By adding a shadow stack regset, it also has the effect of including the shadow stack state in a core dump, which could be useful for debugging. The shadow stack specific xstate includes the SSP, and the shadow stack and WRSS enablement status. Enabling shadow stack or wrss in the kernel involves more than just flipping the bit. The kernel is made aware that it has to do extra things when cloning or handling signals. That logic is triggered off of separate feature enablement state kept in the task struct. So the flipping on HW shadow stack enforcement without notifying the kernel to change its behavior would severely limit what an application could do without crashing, and the results would depend on kernel internal implementation details. There is also no known use for controlling this state via prtace today. So only expose the SSP, which is something that userspace already has indirect control over. Tested-by: Pengfei Xu Tested-by: John Allen Tested-by: Kees Cook Acked-by: Mike Rapoport (IBM) Reviewed-by: Kees Cook Co-developed-by: Rick Edgecombe Signed-off-by: Rick Edgecombe Signed-off-by: Yu-cheng Yu Signed-off-by: Yu-cheng Yu Signed-off-by: Rick Edgecombe Tested-by: Pengfei Xu --- v5: - Check shadow stack enablement status for tracee (rppt) - Fix typo in comment v4: - Make shadow stack only. Reduce to only supporting SSP register, and remove CET references (peterz) - Add comment to not use 0x203, because binutils already looks for it in coredumps. (Christina Schimpe) v3: - Drop dependence on thread.shstk.size, and use thread.features bits - Drop 32 bit support v2: - Check alignment on ssp. - Block IBT bits. - Handle init states instead of returning error. - Add verbose commit log justifying the design. --- arch/x86/include/asm/fpu/regset.h | 7 +-- arch/x86/kernel/fpu/regset.c | 86 +++++++++++++++++++++++++++++++ arch/x86/kernel/ptrace.c | 12 +++++ include/uapi/linux/elf.h | 2 + 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/fpu/regset.h b/arch/x86/include/asm/fpu/regset.h index 4f928d6a367b..697b77e96025 100644 --- a/arch/x86/include/asm/fpu/regset.h +++ b/arch/x86/include/asm/fpu/regset.h @@ -7,11 +7,12 @@ #include -extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active; +extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active, + ssp_active; extern user_regset_get2_fn fpregs_get, xfpregs_get, fpregs_soft_get, - xstateregs_get; + xstateregs_get, ssp_get; extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set, - xstateregs_set; + xstateregs_set, ssp_set; /* * xstateregs_active == regset_fpregs_active. Please refer to the comment diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index 6d056b68f4ed..c806952d9496 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "context.h" #include "internal.h" @@ -174,6 +175,91 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, return ret; } +#ifdef CONFIG_X86_USER_SHADOW_STACK +int ssp_active(struct task_struct *target, const struct user_regset *regset) +{ + if (target->thread.features & ARCH_SHSTK_SHSTK) + return regset->n; + + return 0; +} + +int ssp_get(struct task_struct *target, const struct user_regset *regset, + struct membuf to) +{ + struct fpu *fpu = &target->thread.fpu; + struct cet_user_state *cetregs; + + if (!boot_cpu_has(X86_FEATURE_USER_SHSTK)) + return -ENODEV; + + sync_fpstate(fpu); + cetregs = get_xsave_addr(&fpu->fpstate->regs.xsave, XFEATURE_CET_USER); + if (!cetregs) { + /* + * The registers are the in the init state. The init values for + * these regs are zero, so just zero the output buffer. + */ + membuf_zero(&to, sizeof(cetregs->user_ssp)); + return 0; + } + + return membuf_write(&to, (unsigned long *)&cetregs->user_ssp, + sizeof(cetregs->user_ssp)); +} + +int ssp_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct fpu *fpu = &target->thread.fpu; + struct xregs_state *xsave = &fpu->fpstate->regs.xsave; + struct cet_user_state *cetregs; + unsigned long user_ssp; + int r; + + if (!boot_cpu_has(X86_FEATURE_USER_SHSTK) || + !ssp_active(target, regset)) + return -ENODEV; + + r = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_ssp, 0, -1); + if (r) + return r; + + /* + * Some kernel instructions (IRET, etc) can cause exceptions in the case + * of disallowed CET register values. Just prevent invalid values. + */ + if ((user_ssp >= TASK_SIZE_MAX) || !IS_ALIGNED(user_ssp, 8)) + return -EINVAL; + + fpu_force_restore(fpu); + + /* + * Don't want to init the xfeature until the kernel will definitely + * overwrite it, otherwise if it inits and then fails out, it would + * end up initing it to random data. + */ + if (!xfeature_saved(xsave, XFEATURE_CET_USER) && + WARN_ON(init_xfeature(xsave, XFEATURE_CET_USER))) + return -ENODEV; + + cetregs = get_xsave_addr(xsave, XFEATURE_CET_USER); + if (WARN_ON(!cetregs)) { + /* + * This shouldn't ever be NULL because it was successfully + * inited above if needed. The only scenario would be if an + * xfeature was somehow saved in a buffer, but not enabled in + * xsave. + */ + return -ENODEV; + } + + cetregs->user_ssp = user_ssp; + return 0; +} +#endif /* CONFIG_X86_USER_SHADOW_STACK */ + #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION /* diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index dfaa270a7cc9..095f04bdabdc 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -58,6 +58,7 @@ enum x86_regset_64 { REGSET64_FP, REGSET64_IOPERM, REGSET64_XSTATE, + REGSET64_SSP, }; #define REGSET_GENERAL \ @@ -1267,6 +1268,17 @@ static struct user_regset x86_64_regsets[] __ro_after_init = { .active = ioperm_active, .regset_get = ioperm_get }, +#ifdef CONFIG_X86_USER_SHADOW_STACK + [REGSET64_SSP] = { + .core_note_type = NT_X86_SHSTK, + .n = 1, + .size = sizeof(u64), + .align = sizeof(u64), + .active = ssp_active, + .regset_get = ssp_get, + .set = ssp_set + }, +#endif }; static const struct user_regset_view user_x86_64_view = { diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index 68de6f4c4eee..103a1f2da86e 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -406,6 +406,8 @@ typedef struct elf64_shdr { #define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ #define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +/* Old binutils treats 0x203 as a CET state */ +#define NT_X86_SHSTK 0x204 /* x86 SHSTK state */ #define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ #define NT_S390_TIMER 0x301 /* s390 timer register */ #define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */