From patchwork Mon Nov 7 06:38:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kyle Huey X-Patchwork-Id: 16263 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1875718wru; Sun, 6 Nov 2022 22:48:17 -0800 (PST) X-Google-Smtp-Source: AMsMyM51C/dVkTFjZsdNUDNagTsWwrmdKHfcVd9/iJxlO3aG1XdCVD5M0alp8wzm4oBTmff5QwdV X-Received: by 2002:a17:907:80d:b0:73d:1e3f:3d83 with SMTP id wv13-20020a170907080d00b0073d1e3f3d83mr44891420ejb.372.1667803697465; Sun, 06 Nov 2022 22:48:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1667803697; cv=none; d=google.com; s=arc-20160816; b=yJhZJrrEZlPQrsSMpDWZbEDtz5Vwrn0PPktpd/0dsQIqizobnh9+7ojWNePyJlIU2e BUtyqkq0d3rrsL2F7rCFL0vfs1SE/xIL+I2JR40Fvm+QI9PQ4sPoaEavLQpUxynxRVPf Ea5nkU9TQ9fNihiynIdndFyE7MZiKpblDfzszd5+3nqsGtsvCDplRonrzU96cSeF6aZ9 V2O8yhU9cMH6G/o2e85rE4wwbI3XHOlX6/vahkfCb+R3x7VYr1lrZ2DNsZhTrcXn13e1 6ZsKHqNwOdkAqhbWalDFvA9QGLJ/K65oe4N2eEjXTk4kARKzyZFlPdLZ2w1gInx8bFEb 28Cg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=9mtjXR87V5zH/fMM47wiRGD726rwhb3iIYRWAJHDu0g=; b=mK8KUnaBPxpGK/8M1Nofk5oC+ozmSbTzV/q54qUGfesyukaJDPxq5mO6jqK43J5zaP 1QCacCJXhdfF02HJH+OOUzUGbiqxrYrCdrllObZrg39xgsSkAeG3ElJ7M/gbBOfQaHr9 DRDd4AOMUZk1/By8tKqUdUM9Keau/1wDvacghf0uGMgSOJ3bFKp6iMB9c8IEq2ws5TNh GwLqBH0NrxPVjhAjrHerWBMGtxN67Xg+ZMY7KRZrK6e5QW3xba08Y6ZiCA+ZQCtPS+rR x26KGuRN+yX8KSqt+lPnoGxowPq8viqDzfja7VRvWgTi3pyNrjVqLIwPanv+BZVcSML4 cKpg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kylehuey.com header.s=google header.b=ZFGmnygH; 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 Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ne28-20020a1709077b9c00b007a9c3366e9asi9264840ejc.716.2022.11.06.22.47.53; Sun, 06 Nov 2022 22:48:17 -0800 (PST) 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=@kylehuey.com header.s=google header.b=ZFGmnygH; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230430AbiKGGi3 (ORCPT + 99 others); Mon, 7 Nov 2022 01:38:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48006 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231138AbiKGGi1 (ORCPT ); Mon, 7 Nov 2022 01:38:27 -0500 Received: from mail-pf1-x435.google.com (mail-pf1-x435.google.com [IPv6:2607:f8b0:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D67BAE82 for ; Sun, 6 Nov 2022 22:38:25 -0800 (PST) Received: by mail-pf1-x435.google.com with SMTP id q9so9719953pfg.5 for ; Sun, 06 Nov 2022 22:38:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kylehuey.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9mtjXR87V5zH/fMM47wiRGD726rwhb3iIYRWAJHDu0g=; b=ZFGmnygH/bA8GD6CH49bLrGItI53z8fuVmwSh+8/Ffdw4H02GBBtMU2UWE4yr071W3 m/l98oanMYhVNLk2rL8MpMLIJijsm21roy/Xr/gwwvr+I2Mm0wT2pTx+tTE7TzPJtgS6 MS0JlUoRIFzaAZu5m9awQZbjGmWqWznH4vDvQ2Hbp6IHrI7cO7NlMCXbkSm3bStboLAC hPwYEhIBiCtnYh7VMmupBVz5Fxvp+yRzDiIqBh28FH48sBSN/rUob3pI0aOkt2HMtfji 2MRuokyaj4fB07zimGANpFM9SSGvd1XjWMp5SGMHzaHupNZO8Lg3asi63TYs8GBB39qZ rWEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9mtjXR87V5zH/fMM47wiRGD726rwhb3iIYRWAJHDu0g=; b=D9s4xxLzUaDFPT+IZPlDdcB5E+VoQBuJzD4mgJm7YKm+OXY0l6KbsALQWANUaysWVb pJlVGNjKs8v1ouy+FEuVq2q9+tof4oORFgocimzvvXuZFUE4WT3k5UOClBPyxxmvlJ2s nZhUjsAR3UTKHEYVBi6tPkpqsX/Rz1MsYUJjLXBU/wnfg8KAnypZtDkKUQ8lGA+F0PMu JkrTWPLbuV1ddufxr2NqUsR1ERX4FD0utXqMq9477fy8rIxh+AjqfwVYddHpvL4WgwUw 4W3SrdR7wXQR9RJEbQYuldUGTGRYXKitDg1ev6+XWp+5Iy2xktmTsAPGE1pBWkifuedM SFUw== X-Gm-Message-State: ACrzQf2eLS5eDSavHEhZ6xKbRX/3iluIcsfRqS2bhiA+ivV4fwV57F7V A6YnmaeXfxp5gwKdBH/y730GCA== X-Received: by 2002:a05:6a00:1822:b0:56b:f29d:cca1 with SMTP id y34-20020a056a00182200b0056bf29dcca1mr49595196pfa.65.1667803105304; Sun, 06 Nov 2022 22:38:25 -0800 (PST) Received: from minbar.home.kylehuey.com (c-71-198-251-229.hsd1.ca.comcast.net. [71.198.251.229]) by smtp.gmail.com with ESMTPSA id b20-20020a63d814000000b004468cb97c01sm3453803pgh.56.2022.11.06.22.38.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 06 Nov 2022 22:38:24 -0800 (PST) From: Kyle Huey X-Google-Original-From: Kyle Huey To: Linus Torvalds Cc: Dave Hansen , Thomas Gleixner , Borislav Petkov , Ingo Molnar , x86@kernel.org, "H. Peter Anvin" , Paolo Bonzini , Andy Lutomirski , Peter Zijlstra , Sean Christopherson , linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Robert O'Callahan , David Manouchehri , Kyle Huey , Borislav Petkov , stable@vger.kernel.org Subject: [RESEND PATCH v6 1/2] x86/fpu: Allow PKRU to be (once again) written by ptrace. Date: Sun, 6 Nov 2022 22:38:07 -0800 Message-Id: <20221107063807.81774-2-khuey@kylehuey.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221107063807.81774-1-khuey@kylehuey.com> References: <20221107063807.81774-1-khuey@kylehuey.com> MIME-Version: 1.0 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_NONE, SPF_HELO_NONE,SPF_PASS 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: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1748818930015184267?= X-GMAIL-MSGID: =?utf-8?q?1748818930015184267?= From: Kyle Huey When management of the PKRU register was moved away from XSTATE, emulation of PKRU's existence in XSTATE was added for reading PKRU through ptrace, but not for writing PKRU through ptrace. This can be seen by running gdb and executing `p $pkru`, `set $pkru = 42`, and `p $pkru`. On affected kernels (5.14+) the write to the PKRU register (which gdb performs through ptrace) is ignored. There are three APIs that write PKRU: sigreturn, PTRACE_SETREGSET with NT_X86_XSTATE, and KVM_SET_XSAVE. sigreturn still uses XRSTOR to write to PKRU. KVM_SET_XSAVE has its own special handling to make PKRU writes take effect (in fpu_copy_uabi_to_guest_fpstate). Push that down into copy_uabi_to_xstate and have PTRACE_SETREGSET with NT_X86_XSTATE pass in a pointer to the appropriate PKRU slot. copy_sigframe_from_user_to_xstate depends on copy_uabi_to_xstate populating the PKRU field in the task's XSTATE so that __fpu_restore_sig can do a XRSTOR from it, so continue doing that. This also adds code to initialize the PKRU value to the hardware init value (namely 0) if the PKRU bit is not set in the XSTATE header provided to ptrace, to match XRSTOR. Changelog since v5: - Avoids a second copy from the uabi buffer as suggested. - Preserves old KVM_SET_XSAVE behavior where leaving the PKRU bit in the XSTATE header results in PKRU remaining unchanged instead of reinitializing it. - Fixed up patch metadata as requested. Changelog since v4: - Selftest additionally checks PKRU readbacks through ptrace. - Selftest flips all PKRU bits (except the default key). Changelog since v3: - The v3 patch is now part 1 of 2. - Adds a selftest in part 2 of 2. Changelog since v2: - Removed now unused variables in fpu_copy_uabi_to_guest_fpstate Changelog since v1: - Handles the error case of copy_to_buffer(). Fixes: e84ba47e313d ("x86/fpu: Hook up PKRU into ptrace()") Signed-off-by: Kyle Huey Cc: Dave Hansen Cc: Thomas Gleixner Cc: Borislav Petkov Cc: stable@vger.kernel.org # 5.14+ --- arch/x86/kernel/fpu/core.c | 20 +++++++++----------- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/signal.c | 2 +- arch/x86/kernel/fpu/xstate.c | 25 ++++++++++++++++++++----- arch/x86/kernel/fpu/xstate.h | 4 ++-- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 3b28c5b25e12..c273669e8a00 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -391,8 +391,6 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, { struct fpstate *kstate = gfpu->fpstate; const union fpregs_state *ustate = buf; - struct pkru_state *xpkru; - int ret; if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) { if (ustate->xsave.header.xfeatures & ~XFEATURE_MASK_FPSSE) @@ -406,16 +404,16 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, if (ustate->xsave.header.xfeatures & ~xcr0) return -EINVAL; - ret = copy_uabi_from_kernel_to_xstate(kstate, ustate); - if (ret) - return ret; + /* + * Nullify @vpkru to preserve its current value if PKRU's bit isn't set + * in the header. KVM's odd ABI is to leave PKRU untouched in this + * case (all other components are eventually re-initialized). + * (Not clear that this is actually necessary for compat). + */ + if (!(ustate->xsave.header.xfeatures & XFEATURE_MASK_PKRU)) + vpkru = NULL; - /* Retrieve PKRU if not in init state */ - if (kstate->regs.xsave.header.xfeatures & XFEATURE_MASK_PKRU) { - xpkru = get_xsave_addr(&kstate->regs.xsave, XFEATURE_PKRU); - *vpkru = xpkru->pkru; - } - return 0; + return copy_uabi_from_kernel_to_xstate(kstate, ustate, vpkru); } EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate); #endif /* CONFIG_KVM */ diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index 75ffaef8c299..6d056b68f4ed 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -167,7 +167,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, } fpu_force_restore(fpu); - ret = copy_uabi_from_kernel_to_xstate(fpu->fpstate, kbuf ?: tmpbuf); + ret = copy_uabi_from_kernel_to_xstate(fpu->fpstate, kbuf ?: tmpbuf, &target->thread.pkru); out: vfree(tmpbuf); diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 91d4b6de58ab..558076dbde5b 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -396,7 +396,7 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, fpregs = &fpu->fpstate->regs; if (use_xsave() && !fx_only) { - if (copy_sigframe_from_user_to_xstate(fpu->fpstate, buf_fx)) + if (copy_sigframe_from_user_to_xstate(tsk, buf_fx)) return false; } else { if (__copy_from_user(&fpregs->fxsave, buf_fx, diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index c8340156bfd2..8f14981a3936 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -1197,7 +1197,7 @@ static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size, static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf, - const void __user *ubuf) + const void __user *ubuf, u32 *pkru) { struct xregs_state *xsave = &fpstate->regs.xsave; unsigned int offset, size; @@ -1246,6 +1246,21 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf, } } + /* + * Update the user protection key storage. Allow KVM to + * pass in a NULL pkru pointer if the mask bit is unset + * for its legacy ABI behavior. + */ + if (pkru) + *pkru = 0; + + if (hdr.xfeatures & XFEATURE_MASK_PKRU) { + struct pkru_state *xpkru; + + xpkru = __raw_xsave_addr(xsave, XFEATURE_PKRU); + *pkru = xpkru->pkru; + } + /* * The state that came in from userspace was user-state only. * Mask all the user states out of 'xfeatures': @@ -1264,9 +1279,9 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf, * Convert from a ptrace standard-format kernel buffer to kernel XSAVE[S] * format and copy to the target thread. Used by ptrace and KVM. */ -int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf) +int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru) { - return copy_uabi_to_xstate(fpstate, kbuf, NULL); + return copy_uabi_to_xstate(fpstate, kbuf, NULL, pkru); } /* @@ -1274,10 +1289,10 @@ int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf) * XSAVE[S] format and copy to the target thread. This is called from the * sigreturn() and rt_sigreturn() system calls. */ -int copy_sigframe_from_user_to_xstate(struct fpstate *fpstate, +int copy_sigframe_from_user_to_xstate(struct task_struct *tsk, const void __user *ubuf) { - return copy_uabi_to_xstate(fpstate, NULL, ubuf); + return copy_uabi_to_xstate(tsk->thread.fpu.fpstate, NULL, ubuf, &tsk->thread.pkru); } static bool validate_independent_components(u64 mask) diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h index 5ad47031383b..a4ecb04d8d64 100644 --- a/arch/x86/kernel/fpu/xstate.h +++ b/arch/x86/kernel/fpu/xstate.h @@ -46,8 +46,8 @@ extern void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, u32 pkru_val, enum xstate_copy_mode copy_mode); extern void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk, enum xstate_copy_mode mode); -extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf); -extern int copy_sigframe_from_user_to_xstate(struct fpstate *fpstate, const void __user *ubuf); +extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru); +extern int copy_sigframe_from_user_to_xstate(struct task_struct *tsk, const void __user *ubuf); extern void fpu__init_cpu_xstate(void); From patchwork Mon Nov 7 06:38:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kyle Huey X-Patchwork-Id: 16264 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1876188wru; Sun, 6 Nov 2022 22:49:45 -0800 (PST) X-Google-Smtp-Source: AMsMyM53HJCPjgGqwkQtGukSXdNGBqBSdL5dkD0DvzHqVROAa3fJYrRFayhKjxfikLfIRmUh3Fqe X-Received: by 2002:a50:c34b:0:b0:464:6bcd:da23 with SMTP id q11-20020a50c34b000000b004646bcdda23mr15792694edb.167.1667803785542; Sun, 06 Nov 2022 22:49:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1667803785; cv=none; d=google.com; s=arc-20160816; b=on5oUybtekYpMteY9xRudPYPZjE3/duICujf65tkMj15eKCPFmk5Wns1Y7X/oAcfBK yLr+iP7GeYroOVhynBpLULUT5E1ybJCAbyANIrOl1yWVyzTBvhgCfzX99Oo8bymJ243V lyS2RsACpnLtKjncWP16x82jo5WvllxlPVnMqCWEqPHO0ixzbYWdjX5nmaK6FsrelLfm 5vDFAWz7I5j8IF++3jLBg2jd2tMmgQossHGKCyDjIn/ld351P2Hbc+5G8/HAhLzpMOr+ Z7fN9x2yvSyt0gpuaNsTYgAXlJHbW7T8oxBCiBfgFtGf26O5tlldMoGfFJ22yqH8XIci MW4Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=BvEzpa366uwfXvIWXqplMREsN3llp6jn3XS48IWwJVU=; b=d60VRk/L+jBHMyKFRBqQA4P2xN1XA5ttlWtoJV3gA9xsSXpAx6o+Tk4hwOGv5h0nq2 vZuDavhr3z/lRrQ4s6yE2fa+b7BwHU3i32yrvmCbwz1+lJOlrxoRERW8PnFDvlhm/gf4 1t+LIVB5Ln0FfZpYwSAPcdO4rsdIlwTIt+t8ry91bqTj6nV2qvsaM+XYmgAB+gLFyF/S wZhnRfUXjVjzqyCPIGIehBuT/4JPN9AuWdo1lPWfBh4JOm1Rs4SmrxaByAquhp7VqKs2 sNEQoM5JP7p8Vd8aSzBWcwLbGfp2xdOEp/JSv5+fALp9gRfupgOm033GR1B2NoJsZ7pW P7JA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kylehuey.com header.s=google header.b=JbvFkHTg; 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 Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id mp3-20020a1709071b0300b0078d0f57b0e2si8957957ejc.412.2022.11.06.22.49.21; Sun, 06 Nov 2022 22:49:45 -0800 (PST) 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=@kylehuey.com header.s=google header.b=JbvFkHTg; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231391AbiKGGid (ORCPT + 99 others); Mon, 7 Nov 2022 01:38:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48044 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231373AbiKGGi2 (ORCPT ); Mon, 7 Nov 2022 01:38:28 -0500 Received: from mail-pg1-x52b.google.com (mail-pg1-x52b.google.com [IPv6:2607:f8b0:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 92BB3E82 for ; Sun, 6 Nov 2022 22:38:27 -0800 (PST) Received: by mail-pg1-x52b.google.com with SMTP id b62so9647640pgc.0 for ; Sun, 06 Nov 2022 22:38:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kylehuey.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BvEzpa366uwfXvIWXqplMREsN3llp6jn3XS48IWwJVU=; b=JbvFkHTg6F3sZyinEDT4lwm/oP2vJjWifwvuI06HryqR3mSh9b1yubfFMtwo5ZR3Y1 JbbbdfUeRw4rpOEBeBFTZ/yFFQxcJR3Z5xIcDeQLx9WtUS59mLXzorgJaqTTzKiziJQ0 yxqXeJh0PFM/EE95MrnIEDzRQM4d1p+LK7gXp0mZsqvnNx27Rweu9QmShysofFnSgtr6 zYHDChv8prjwyglRUgKAh6M84nkJ+k1RaXXdvHY75liLUxh5nGIu6/5hexcO71IZI/ma jet2ZMKl+bt99S3q/qjspXQGzaLoOTUVimHeeLYUIEnpdheeLh+S10Lkiksnz+OOQiTn EEhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BvEzpa366uwfXvIWXqplMREsN3llp6jn3XS48IWwJVU=; b=xdrCIHX1g0lJekOTbBdnNcpQYZMqfRwH6MMXMcQcePIOvkAjRzOWNZzm9XpiuMtzG9 zIS5bnP+EegSqdBT5Z2KxzA3VQ7oc4FqKdZ8nR5G1eP+xY4OIoErvAzKTehiz8v4lj// KzK+ZOZxLnZFTdEQPt22TrRFsXsWPyoNQWUl4DaBS8kbfO5zAxqvgDMHIW1j54W9sV5e fOP4XyUOppDiOSV9oyF8AaQBYmt3XO9DAfXvZNPdRxIZm2W+aczbTvULct2iHROeHgkV MCDloRnGGQ2mhyu3uh1dTQ1t8HkKf08e1xLwAifPySidO1puRVCYX9h6K2hp2S+B5LSZ a2yA== X-Gm-Message-State: ACrzQf16TJLComtlitdLjL8sN/biUaSk2NrJli95GDZhW4Ur/f68BEcR zoQCm36+yZPkPxyixJIF2mVXTw== X-Received: by 2002:a63:2547:0:b0:46f:793f:197b with SMTP id l68-20020a632547000000b0046f793f197bmr42505736pgl.35.1667803107020; Sun, 06 Nov 2022 22:38:27 -0800 (PST) Received: from minbar.home.kylehuey.com (c-71-198-251-229.hsd1.ca.comcast.net. [71.198.251.229]) by smtp.gmail.com with ESMTPSA id b20-20020a63d814000000b004468cb97c01sm3453803pgh.56.2022.11.06.22.38.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 06 Nov 2022 22:38:26 -0800 (PST) From: Kyle Huey X-Google-Original-From: Kyle Huey To: Linus Torvalds Cc: Dave Hansen , Thomas Gleixner , Borislav Petkov , Ingo Molnar , x86@kernel.org, "H. Peter Anvin" , Paolo Bonzini , Andy Lutomirski , Peter Zijlstra , Sean Christopherson , linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Robert O'Callahan , David Manouchehri , Kyle Huey Subject: [RESEND PATCH v6 2/2] selftests/vm/pkeys: Add a regression test for setting PKRU through ptrace Date: Sun, 6 Nov 2022 22:38:08 -0800 Message-Id: <20221107063807.81774-3-khuey@kylehuey.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221107063807.81774-1-khuey@kylehuey.com> References: <20221107063807.81774-1-khuey@kylehuey.com> MIME-Version: 1.0 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_NONE, SPF_HELO_NONE,SPF_PASS 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: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1748819021997366261?= X-GMAIL-MSGID: =?utf-8?q?1748819021997366261?= From: Kyle Huey This tests PTRACE_SETREGSET with NT_X86_XSTATE modifying PKRU directly and removing the PKRU bit from XSTATE_BV. Signed-off-by: Kyle Huey --- tools/testing/selftests/vm/pkey-x86.h | 12 ++ tools/testing/selftests/vm/protection_keys.c | 131 ++++++++++++++++++- 2 files changed, 141 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/vm/pkey-x86.h b/tools/testing/selftests/vm/pkey-x86.h index b078ce9c6d2a..72c14cd3ddc7 100644 --- a/tools/testing/selftests/vm/pkey-x86.h +++ b/tools/testing/selftests/vm/pkey-x86.h @@ -104,6 +104,18 @@ static inline int cpu_has_pkeys(void) return 1; } +static inline int cpu_max_xsave_size(void) +{ + unsigned long XSTATE_CPUID = 0xd; + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + + __cpuid_count(XSTATE_CPUID, 0, eax, ebx, ecx, edx); + return ecx; +} + static inline u32 pkey_bit_position(int pkey) { return pkey * PKEY_BITS_PER_PKEY; diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c index 291bc1e07842..95f403a0c46d 100644 --- a/tools/testing/selftests/vm/protection_keys.c +++ b/tools/testing/selftests/vm/protection_keys.c @@ -18,12 +18,13 @@ * do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks * * Compile like this: - * gcc -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm - * gcc -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm + * gcc -mxsave -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm + * gcc -mxsave -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm */ #define _GNU_SOURCE #define __SANE_USERSPACE_TYPES__ #include +#include #include #include #include @@ -1550,6 +1551,129 @@ void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey) do_not_expect_pkey_fault("plain read on recently PROT_EXEC area"); } +#if defined(__i386__) || defined(__x86_64__) +void test_ptrace_modifies_pkru(int *ptr, u16 pkey) +{ + u32 new_pkru; + pid_t child; + int status, ret; + int pkey_offset = pkey_reg_xstate_offset(); + size_t xsave_size = cpu_max_xsave_size(); + void *xsave; + u32 *pkey_register; + u64 *xstate_bv; + struct iovec iov; + + new_pkru = ~read_pkey_reg(); + /* Don't make PROT_EXEC mappings inaccessible */ + new_pkru &= ~3; + + child = fork(); + pkey_assert(child >= 0); + dprintf3("[%d] fork() ret: %d\n", getpid(), child); + if (!child) { + ptrace(PTRACE_TRACEME, 0, 0, 0); + /* Stop and allow the tracer to modify PKRU directly */ + raise(SIGSTOP); + + /* + * need __read_pkey_reg() version so we do not do shadow_pkey_reg + * checking + */ + if (__read_pkey_reg() != new_pkru) + exit(1); + + /* Stop and allow the tracer to clear XSTATE_BV for PKRU */ + raise(SIGSTOP); + + if (__read_pkey_reg() != 0) + exit(1); + + /* Stop and allow the tracer to examine PKRU */ + raise(SIGSTOP); + + exit(0); + } + + pkey_assert(child == waitpid(child, &status, 0)); + dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); + pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); + + xsave = (void *)malloc(xsave_size); + pkey_assert(xsave > 0); + + /* Modify the PKRU register directly */ + iov.iov_base = xsave; + iov.iov_len = xsave_size; + ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); + pkey_assert(ret == 0); + + pkey_register = (u32 *)(xsave + pkey_offset); + pkey_assert(*pkey_register == read_pkey_reg()); + + *pkey_register = new_pkru; + + ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov); + pkey_assert(ret == 0); + + /* Test that the modification is visible in ptrace before any execution */ + memset(xsave, 0xCC, xsave_size); + ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); + pkey_assert(ret == 0); + pkey_assert(*pkey_register == new_pkru); + + /* Execute the tracee */ + ret = ptrace(PTRACE_CONT, child, 0, 0); + pkey_assert(ret == 0); + + /* Test that the tracee saw the PKRU value change */ + pkey_assert(child == waitpid(child, &status, 0)); + dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); + pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); + + /* Test that the modification is visible in ptrace after execution */ + memset(xsave, 0xCC, xsave_size); + ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); + pkey_assert(ret == 0); + pkey_assert(*pkey_register == new_pkru); + + /* Clear the PKRU bit from XSTATE_BV */ + xstate_bv = (u64 *)(xsave + 512); + *xstate_bv &= ~(1 << 9); + + ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov); + pkey_assert(ret == 0); + + /* Test that the modification is visible in ptrace before any execution */ + memset(xsave, 0xCC, xsave_size); + ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); + pkey_assert(ret == 0); + pkey_assert(*pkey_register == 0); + + ret = ptrace(PTRACE_CONT, child, 0, 0); + pkey_assert(ret == 0); + + /* Test that the tracee saw the PKRU value go to 0 */ + pkey_assert(child == waitpid(child, &status, 0)); + dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); + pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); + + /* Test that the modification is visible in ptrace after execution */ + memset(xsave, 0xCC, xsave_size); + ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov); + pkey_assert(ret == 0); + pkey_assert(*pkey_register == 0); + + ret = ptrace(PTRACE_CONT, child, 0, 0); + pkey_assert(ret == 0); + pkey_assert(child == waitpid(child, &status, 0)); + dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status); + pkey_assert(WIFEXITED(status)); + pkey_assert(WEXITSTATUS(status) == 0); + free(xsave); +} +#endif + void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey) { int size = PAGE_SIZE; @@ -1585,6 +1709,9 @@ void (*pkey_tests[])(int *ptr, u16 pkey) = { test_pkey_syscalls_bad_args, test_pkey_alloc_exhaust, test_pkey_alloc_free_attach_pkey0, +#if defined(__i386__) || defined(__x86_64__) + test_ptrace_modifies_pkru, +#endif }; void run_tests_once(void)