From nobody Tue Dec 16 03:22:37 2025 Received: from mx0a-00069f02.pphosted.com (mx0a-00069f02.pphosted.com [205.220.165.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5E3BB16F27E for ; Tue, 28 May 2024 14:43:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.165.32 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907424; cv=none; b=Pfh3ws7sGP8/bJEZKqgAGk0xIgWEZ7t+Gs4l3DEjYAgmA3gf8R8pZESmdEXzNSTO4i0RW5jicLf1nfpyiTLL2gQV26ctMWVMSo7OcAe+/r5iluDTdub4ebdL2SKEH2M2UEa3FJH20JuGGl4uMOKtj1wFq+jS6jVGAA7ylIfXrN0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907424; c=relaxed/simple; bh=xRBtbxLMzh49QddBZgDAH2CFH4T6i5yktzrkn+9i++U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=cSdYfNzG8L9Q+Z7uyew0Gagzbr083/WU3lbuBWjDKrXfW4KzS+sEiBmffdwTp8PkB4T+RGPcXUnzgPP5+EGDwcjRH7yBh0iwFKYVklP2NFO1KjUDsuDps7F0tf/hY46knLoctx7gCM3Lj/ELfE+E92jg7LmxzlSjMnilaSC5g6U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com; spf=pass smtp.mailfrom=oracle.com; arc=none smtp.client-ip=205.220.165.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oracle.com Received: from pps.filterd (m0246629.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44SBorRU020154; Tue, 28 May 2024 14:43:35 GMT DKIM-Signature: =?UTF-8?Q?v=3D1;_a=3Drsa-sha256;_c=3Drelaxed/relaxed;_d=3Doracle.com;_h?= =?UTF-8?Q?=3Dcc:content-transfer-encoding:date:from:in-reply-to:message-i?= =?UTF-8?Q?d:mime-version:references:subject:to;_s=3Dcorp-2023-11-20;_bh?= =?UTF-8?Q?=3DH9cdt3lpPMrTDH2HH5AJwUAq5CiV1r3IfA2xEocJ7Ww=3D;_b=3DJwzg3JCm?= =?UTF-8?Q?W2MPH6QINpOLZrzmjW4ijeoRKZRmpvgf/SrBOG9po4kaxT4F/jnc+3IKGXRG_x6?= =?UTF-8?Q?EcerbojpTDHIXIYpbGLgLmx9ebQUOT95ob/QxlCCoaj738z0DDYUO2rh3GCfMnJ?= =?UTF-8?Q?+2k_NF3zwpPh7mc9WHNoPQ6WKQS04yhmjIHIVjTcQ680PACtqPHgRXvSNDPVIOI?= =?UTF-8?Q?yLKQFOcsv_r34D5Q34NJ2050TsS38Qc9o4b6XAmJHcRQDGhVcbGygMzgTiKq0ZO?= =?UTF-8?Q?5DtvzscztkBoAob_W3sucUaZ5gWXm1yshYeEMHNUawlC3cviX2G58ejkNcNn0zZ?= =?UTF-8?Q?xLezNE/raBei0qQF3XDtZ_Yw=3D=3D_?= Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3yb8p7meru-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:34 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 44SER3sU025784; Tue, 28 May 2024 14:43:34 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3yc50py1j2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:34 +0000 Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44SEhW7r035350; Tue, 28 May 2024 14:43:33 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3yc50py1g5-2; Tue, 28 May 2024 14:43:33 +0000 From: Aruna Ramakrishna To: linux-kernel@vger.kernel.org Cc: x86@kernel.org, dave.hansen@linux.intel.com, tglx@linutronix.de, mingo@kernel.org, keith.lucas@oracle.com, aruna.ramakrishna@oracle.com Subject: [PATCH v4 1/5] x86/pkeys: Add PKRU as a parameter in signal handling functions Date: Tue, 28 May 2024 14:43:27 +0000 Message-Id: <20240528144331.2758104-2-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> References: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.12.28.16 definitions=2024-05-28_10,2024-05-28_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 spamscore=0 suspectscore=0 adultscore=0 phishscore=0 malwarescore=0 mlxlogscore=999 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405280111 X-Proofpoint-ORIG-GUID: V89zxVvVeUVPybjM2IFzMjjOR7l6xC_2 X-Proofpoint-GUID: V89zxVvVeUVPybjM2IFzMjjOR7l6xC_2 Content-Type: text/plain; charset="utf-8" Problem description: Let's assume there's a multithreaded application that runs untrusted user code. Each thread has its stack/code protected by a non-zero pkey, and the PKRU register is set up such that only that particular non-zero pkey is enabled. Each thread also sets up an alternate signal stack to handle signals, which is protected by pkey zero. The pkeys man page documents that the PKRU will be reset to init_pkru when the signal handler is invoked, which means that pkey zero access will be enabled. But this reset happens after the kernel attempts to push fpu state to the alternate stack, which is not (yet) accessible by the kernel, which leads to a new SIGSEGV being sent to the application, terminating it. Enabling both the non-zero pkey (for the thread) and pkey zero in userspace will not work for this use case. We cannot have the alt stack writeable by all - the rationale here is that the code running in that thread (using a non-zero pkey) is untrusted and should not have access to the alternate signal stack (that uses pkey zero), to prevent the return address of a function from being changed. The expectation is that kernel should be able to set up the alternate signal stack and deliver the signal to the application even if pkey zero is explicitly disabled by the application. The signal handler accessibility should not be dictated by whatever PKRU value the thread sets up. Solution: The PKRU register is managed by XSAVE, which means the sigframe contents must match the register contents - which is not the case here. We want the sigframe to contain the user-defined PKRU value (so that it is restored correctly from sigcontext) but the actual register must be reset to init_pkru so that the alt stack is accessible and the signal can be delivered to the application. It seems that the proper fix here would be to remove PKRU from the XSAVE framework and manage it separately, which is quite complicated. As a workaround, do this: orig_pkru =3D rdpkru(); wrpkru(orig_pkru & init_pkru_value); xsave_to_user_sigframe(); put_user(pkru_sigframe_addr, orig_pkru) This change is split over multiple patches. In preparation for writing PKRU to sigframe in a later patch, pass in PKRU = as an additional parameter down the chain from handle_signal: setup_rt_frame() xxx_setup_rt_frame() get_sigframe() copy_fpstate_to_sigframe() copy_fpregs_to_sigframe() There are no functional changes in this patch. Signed-off-by: Aruna Ramakrishna --- arch/x86/include/asm/fpu/signal.h | 2 +- arch/x86/include/asm/sighandling.h | 10 +++++----- arch/x86/kernel/fpu/signal.c | 6 +++--- arch/x86/kernel/signal.c | 19 ++++++++++--------- arch/x86/kernel/signal_32.c | 8 ++++---- arch/x86/kernel/signal_64.c | 8 ++++---- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/s= ignal.h index 611fa41711af..eccc75bc9c4f 100644 --- a/arch/x86/include/asm/fpu/signal.h +++ b/arch/x86/include/asm/fpu/signal.h @@ -29,7 +29,7 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, =20 unsigned long fpu__get_fpstate_size(void); =20 -extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, in= t size); +extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, in= t size, u32 pkru); extern void fpu__clear_user_states(struct fpu *fpu); extern bool fpu__restore_sig(void __user *buf, int ia32_frame); =20 diff --git a/arch/x86/include/asm/sighandling.h b/arch/x86/include/asm/sigh= andling.h index e770c4fc47f4..de458354a3ea 100644 --- a/arch/x86/include/asm/sighandling.h +++ b/arch/x86/include/asm/sighandling.h @@ -17,11 +17,11 @@ void signal_fault(struct pt_regs *regs, void __user *fr= ame, char *where); =20 void __user * get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size, - void __user **fpstate); + void __user **fpstate, u32 pkru); =20 -int ia32_setup_frame(struct ksignal *ksig, struct pt_regs *regs); -int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs); -int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs); -int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs); +int ia32_setup_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pkru); +int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pk= ru); +int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pkr= u); +int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pkr= u); =20 #endif /* _ASM_X86_SIGHANDLING_H */ diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 247f2225aa9f..2b3b9e140dd4 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -156,7 +156,7 @@ static inline bool save_xstate_epilog(void __user *buf,= int ia32_frame, return !err; } =20 -static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) +static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, = u32 pkru) { if (use_xsave()) return xsave_to_user_sigframe(buf); @@ -185,7 +185,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_= state __user *buf) * For [f]xsave state, update the SW reserved fields in the [f]xsave frame * indicating the absence/presence of the extended state to the user. */ -bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int s= ize) +bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int s= ize, u32 pkru) { struct task_struct *tsk =3D current; struct fpstate *fpstate =3D tsk->thread.fpu.fpstate; @@ -228,7 +228,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __= user *buf_fx, int size) fpregs_restore_userregs(); =20 pagefault_disable(); - ret =3D copy_fpregs_to_sigframe(buf_fx); + ret =3D copy_fpregs_to_sigframe(buf_fx, pkru); pagefault_enable(); fpregs_unlock(); =20 diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 31b6f5dddfc2..94b894437327 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -74,7 +74,7 @@ static inline int is_x32_frame(struct ksignal *ksig) */ void __user * get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size, - void __user **fpstate) + void __user **fpstate, u32 pkru) { struct k_sigaction *ka =3D &ksig->ka; int ia32_frame =3D is_ia32_frame(ksig); @@ -139,7 +139,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs= , size_t frame_size, } =20 /* save i387 and extended state */ - if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size)) + if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size,= pkru)) return (void __user *)-1L; =20 return (void __user *)sp; @@ -206,7 +206,7 @@ unsigned long get_sigframe_size(void) } =20 static int -setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) +setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pkru) { /* Perform fixup for the pre-signal frame. */ rseq_signal_deliver(ksig, regs); @@ -214,21 +214,22 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *= regs) /* Set up the stack frame */ if (is_ia32_frame(ksig)) { if (ksig->ka.sa.sa_flags & SA_SIGINFO) - return ia32_setup_rt_frame(ksig, regs); + return ia32_setup_rt_frame(ksig, regs, pkru); else - return ia32_setup_frame(ksig, regs); + return ia32_setup_frame(ksig, regs, pkru); } else if (is_x32_frame(ksig)) { - return x32_setup_rt_frame(ksig, regs); + return x32_setup_rt_frame(ksig, regs, pkru); } else { - return x64_setup_rt_frame(ksig, regs); + return x64_setup_rt_frame(ksig, regs, pkru); } } =20 static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) { - bool stepping, failed; struct fpu *fpu =3D ¤t->thread.fpu; + u32 pkru =3D read_pkru(); + bool stepping, failed; =20 if (v8086_mode(regs)) save_v86_state((struct kernel_vm86_regs *) regs, VM86_SIGNAL); @@ -264,7 +265,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *reg= s) if (stepping) user_disable_single_step(current); =20 - failed =3D (setup_rt_frame(ksig, regs) < 0); + failed =3D (setup_rt_frame(ksig, regs, pkru) < 0); if (!failed) { /* * Clear the direction flag as per the ABI for function entry. diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index c12624bc82a3..68f2bfd7d6e7 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c @@ -228,7 +228,7 @@ do { \ goto label; \ } while(0) =20 -int ia32_setup_frame(struct ksignal *ksig, struct pt_regs *regs) +int ia32_setup_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pkru) { sigset32_t *set =3D (sigset32_t *) sigmask_to_save(); struct sigframe_ia32 __user *frame; @@ -246,7 +246,7 @@ int ia32_setup_frame(struct ksignal *ksig, struct pt_re= gs *regs) 0x80cd, /* int $0x80 */ }; =20 - frame =3D get_sigframe(ksig, regs, sizeof(*frame), &fp); + frame =3D get_sigframe(ksig, regs, sizeof(*frame), &fp, pkru); =20 if (ksig->ka.sa.sa_flags & SA_RESTORER) { restorer =3D ksig->ka.sa.sa_restorer; @@ -299,7 +299,7 @@ int ia32_setup_frame(struct ksignal *ksig, struct pt_re= gs *regs) return -EFAULT; } =20 -int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) +int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pk= ru) { sigset32_t *set =3D (sigset32_t *) sigmask_to_save(); struct rt_sigframe_ia32 __user *frame; @@ -319,7 +319,7 @@ int ia32_setup_rt_frame(struct ksignal *ksig, struct pt= _regs *regs) 0, }; =20 - frame =3D get_sigframe(ksig, regs, sizeof(*frame), &fp); + frame =3D get_sigframe(ksig, regs, sizeof(*frame), &fp, pkru); =20 if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 23d8aaf8d9fd..6b189de005b5 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@ -161,7 +161,7 @@ static unsigned long frame_uc_flags(struct pt_regs *reg= s) return flags; } =20 -int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) +int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pkr= u) { sigset_t *set =3D sigmask_to_save(); struct rt_sigframe __user *frame; @@ -172,7 +172,7 @@ int x64_setup_rt_frame(struct ksignal *ksig, struct pt_= regs *regs) if (!(ksig->ka.sa.sa_flags & SA_RESTORER)) return -EFAULT; =20 - frame =3D get_sigframe(ksig, regs, sizeof(struct rt_sigframe), &fp); + frame =3D get_sigframe(ksig, regs, sizeof(struct rt_sigframe), &fp, pkru); uc_flags =3D frame_uc_flags(regs); =20 if (!user_access_begin(frame, sizeof(*frame))) @@ -300,7 +300,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user= *to, return __copy_siginfo_to_user32(to, from); } =20 -int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) +int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, u32 pkr= u) { compat_sigset_t *set =3D (compat_sigset_t *) sigmask_to_save(); struct rt_sigframe_x32 __user *frame; @@ -311,7 +311,7 @@ int x32_setup_rt_frame(struct ksignal *ksig, struct pt_= regs *regs) if (!(ksig->ka.sa.sa_flags & SA_RESTORER)) return -EFAULT; =20 - frame =3D get_sigframe(ksig, regs, sizeof(*frame), &fp); + frame =3D get_sigframe(ksig, regs, sizeof(*frame), &fp, pkru); =20 uc_flags =3D frame_uc_flags(regs); =20 --=20 2.39.3 From nobody Tue Dec 16 03:22:37 2025 Received: from mx0a-00069f02.pphosted.com (mx0a-00069f02.pphosted.com [205.220.165.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC46B16F91E for ; Tue, 28 May 2024 14:43:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.165.32 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907424; cv=none; b=QWVhr/a4irUfS2g80wbnTO+LBx8oLB/yhwaFEaYjSV/GgmbiBL5P8F0au0AysXrgT/WS3PoiUSZcp0SSw+JI3EPWnseuIBg76ujtz3eVqx02ntmUt7yj4v6R7JzhmIYvLxX2dChhe6d/3L4wyVYoYRNkXL2lnO3im6b9U3R8lC0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907424; c=relaxed/simple; bh=/SIaL3B++/HJR73gXBkcankPIIngPsvJL8/+fDzZ7lc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nylYiNbE0WJfB8Okrx2fSNIBRvCfTXnhEbTBH/Xzk/fnCW8SCwRej5pZGfrOltjmoglusUhbzPdOgCDpbZPrP+pX2oC5laZp9Fg1pidi5i2Vl/dQ0eHWPW0x2JFa9l/VZC2Kx5uBgukOJAGbG5sx0njrQknXz6g7UTJYAbMx/eg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com; spf=pass smtp.mailfrom=oracle.com; arc=none smtp.client-ip=205.220.165.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oracle.com Received: from pps.filterd (m0246617.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44SBomRp011696; Tue, 28 May 2024 14:43:36 GMT DKIM-Signature: =?UTF-8?Q?v=3D1;_a=3Drsa-sha256;_c=3Drelaxed/relaxed;_d=3Doracle.com;_h?= =?UTF-8?Q?=3Dcc:content-transfer-encoding:date:from:in-reply-to:message-i?= =?UTF-8?Q?d:mime-version:references:subject:to;_s=3Dcorp-2023-11-20;_bh?= =?UTF-8?Q?=3DnXGGNcr2dE6UFV4afJQdsoWXk+66We/+7H9jhPp/wLw=3D;_b=3DUqUwZoIg?= =?UTF-8?Q?UOisatMUlDvuvgQAOgPBX1yxyH+fmPX6Z3I5zyf2xJof4TWpsCVkOGEd+QR8_Xc?= =?UTF-8?Q?LibkhIHWueGE5Jqj7fbdnBVG4NqVIMNLfVy7SVWn/mpWNjJHE/ZAPyGUF6KgBX7?= =?UTF-8?Q?HeW_8E+XjYc7KkvoLklbmz9+4ZOsgnGvfmfH05AYEXHaWHzDy1dOVEgJTZa+9mj?= =?UTF-8?Q?L9wvNOw4z_QoCMZtluFkQuxTch7LmiJLrbDUy9wMcONGX1qW6PmLHMFoxBY/gUa?= =?UTF-8?Q?piEWQkjYRCgVMqu_VbCNIWxZsURAZXEzodcAVRgeLJHlb3izfGKn218OqPYNjcB?= =?UTF-8?Q?jPselEuDSXEhkabZGQ7Hi_mQ=3D=3D_?= Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3yb8hu4jrr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:35 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 44SENKvI025732; Tue, 28 May 2024 14:43:35 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3yc50py1jv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:35 +0000 Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44SEhW7t035350; Tue, 28 May 2024 14:43:34 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3yc50py1g5-3; Tue, 28 May 2024 14:43:34 +0000 From: Aruna Ramakrishna To: linux-kernel@vger.kernel.org Cc: x86@kernel.org, dave.hansen@linux.intel.com, tglx@linutronix.de, mingo@kernel.org, keith.lucas@oracle.com, aruna.ramakrishna@oracle.com Subject: [PATCH v4 2/5] x86/pkeys: Add helper functions to update PKRU on sigframe Date: Tue, 28 May 2024 14:43:28 +0000 Message-Id: <20240528144331.2758104-3-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> References: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.12.28.16 definitions=2024-05-28_10,2024-05-28_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 spamscore=0 suspectscore=0 adultscore=0 phishscore=0 malwarescore=0 mlxlogscore=999 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405280111 X-Proofpoint-ORIG-GUID: onRcYbw1Bjnw9Hrbb3sjySQsJJ3rUp1x X-Proofpoint-GUID: onRcYbw1Bjnw9Hrbb3sjySQsJJ3rUp1x Content-Type: text/plain; charset="utf-8" In the case where a user thread sets up an alternate signal stack protected by the default pkey (i.e. pkey 0), while the thread's stack is protected by a non-zero pkey, both these pkeys have to be enabled in the PKRU register for the signal to be delivered to the application correctly. However, the PKRU value restored after handling the signal must not enable this extra pkey (i.e. pkey 0), so the PKRU value on the on the sigframe should be overwritten with the user-defined value. Add helper functions that will update PKRU value on the sigframe after XSAVE. These functions will be called in a later patch; this patch does not change any behavior as yet. Signed-off-by: Aruna Ramakrishna --- arch/x86/kernel/fpu/signal.c | 11 +++++++++++ arch/x86/kernel/fpu/xstate.c | 13 +++++++++++++ arch/x86/kernel/fpu/xstate.h | 1 + arch/x86/kernel/signal.c | 15 +++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 2b3b9e140dd4..b0b254b931fd 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -63,6 +63,16 @@ static inline bool check_xstate_in_sigframe(struct fxreg= s_state __user *fxbuf, return true; } =20 +/* + * Update the value of PKRU register that was already pushed onto the sign= al frame. + */ +static inline int update_pkru_in_sigframe(struct xregs_state __user *buf, = u32 pkru) +{ + if (unlikely(!cpu_feature_enabled(X86_FEATURE_OSPKE))) + return 0; + return __put_user(pkru, (unsigned int __user *)get_xsave_addr_user(buf, X= FEATURE_PKRU)); +} + /* * Signal frame handlers. */ @@ -160,6 +170,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_= state __user *buf, u32 pk { if (use_xsave()) return xsave_to_user_sigframe(buf); + if (use_fxsr()) return fxsave_to_user_sigframe((struct fxregs_state __user *) buf); else diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 33a214b1a4ce..e257478a0962 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -992,6 +992,19 @@ void *get_xsave_addr(struct xregs_state *xsave, int xf= eature_nr) return __raw_xsave_addr(xsave, xfeature_nr); } =20 +/* + * Given an xstate feature nr, calculate where in the xsave buffer the sta= te is. + * The xsave buffer should be in standard format, not compacted (e.g. user= mode + * signal frames). + */ +void __user *get_xsave_addr_user(struct xregs_state __user *xsave, int xfe= ature_nr) +{ + if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr))) + return NULL; + + return (void __user *)xsave + xstate_offsets[xfeature_nr]; +} + #ifdef CONFIG_ARCH_HAS_PKEYS =20 /* diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h index 19ca623ffa2a..236742db69fa 100644 --- a/arch/x86/kernel/fpu/xstate.h +++ b/arch/x86/kernel/fpu/xstate.h @@ -55,6 +55,7 @@ extern void fpu__init_cpu_xstate(void); extern void fpu__init_system_xstate(unsigned int legacy_size); =20 extern void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr); +extern void __user *get_xsave_addr_user(struct xregs_state *xsave, int xfe= ature_nr); =20 static inline u64 xfeatures_mask_supervisor(void) { diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 94b894437327..3fa66b2fe753 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -224,6 +224,21 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *r= egs, u32 pkru) } } =20 +/* + * Enable init_pkru pkey as well as the user-defined pkey to ensure that b= oth + * the current stack and the alternate signal stack are writeable. + * Note: this function assumes that the alternate signal stack is accessib= le + * with the init_pkru_value. If the sigaltstack is protected by a differen= t, + * non-zero pkey, then the application will segfault. + */ +static inline u32 sig_prepare_pkru(void) +{ + u32 orig_pkru =3D read_pkru(); + + write_pkru(orig_pkru & pkru_get_init_value()); + return orig_pkru; +} + static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) { --=20 2.39.3 From nobody Tue Dec 16 03:22:37 2025 Received: from mx0a-00069f02.pphosted.com (mx0a-00069f02.pphosted.com [205.220.165.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E634816FF27 for ; Tue, 28 May 2024 14:43:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.165.32 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907424; cv=none; b=AyAD/ZuJuONokE7lG/AnzEBL7Got2jWTIS97g//fBMvsqedLIVi2aZfP0HASGWvXyYOdvEo5tIprL1AQwMJAcMbjRJ/A6RW/Fe/v1I2mMRdIOJI9Ynd4a2BTeZgTAvaYETrBuXNngX2qvjIlUHAeSSJjX8l4EtQ2ndq9joJyc9U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907424; c=relaxed/simple; bh=byLEVOEAyGF2WqnaDcyJv5bVHKJ/dSgrdufHxeMItgY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=hx+bf2rkLqZCq10wcGlLowxKqrBWGTBb7H/SFHlA9tGN7h6Jh2k9rFpepxLjz+RqJ7mIyJDHE05bEolaBqlZUvQSqoTzdS1L2bp0g7hk+OS3VELgonw6JDPn9sLaryrG6p5LjNlCadSIIliQH7p/0Aj5QWDiMoN9yuArV+9+ksw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com; spf=pass smtp.mailfrom=oracle.com; arc=none smtp.client-ip=205.220.165.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oracle.com Received: from pps.filterd (m0246627.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44SBoe6s028715; Tue, 28 May 2024 14:43:37 GMT DKIM-Signature: =?UTF-8?Q?v=3D1;_a=3Drsa-sha256;_c=3Drelaxed/relaxed;_d=3Doracle.com;_h?= =?UTF-8?Q?=3Dcc:content-transfer-encoding:date:from:in-reply-to:message-i?= =?UTF-8?Q?d:mime-version:references:subject:to;_s=3Dcorp-2023-11-20;_bh?= =?UTF-8?Q?=3DnqR21MDKuxMT1J9GlTYAm6s4qP6FtJSxTQTSf2k0Uf8=3D;_b=3DEX6aVNYT?= =?UTF-8?Q?pxpdW0HFvAi26ft5ixWR7ipjgPfStKQ9um8sUGU6Y4jn6h9cvmRcInFVWdxD_WS?= =?UTF-8?Q?EG3eHpvKm4NOjRLT0lny/JIofurzgWQkTM68BiHej17wtUNeL0GmlAvS4Z3TXEx?= =?UTF-8?Q?PNh_tcGjXY/yBtKRQxQnTdRPz9/bM4K22DL3OU0jwwhLao/A44iwmps/keQSgB/?= =?UTF-8?Q?SjNKkoY+s_A1LasH3AegroZ18Nq8jHp9jPwlnNLeImitkBQUrWsM9Zx/0Rv1Drn?= =?UTF-8?Q?u8rGAEm5fSbosfi_YDrioGSlStTwVHBqmsX3fcHoo8DlnLgM7Zs2mSnJ4lzmbjJ?= =?UTF-8?Q?t8khySCVuMd8xZrzxoCgn_gQ=3D=3D_?= Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3yb8hg4jdv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:36 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 44SE3K5g025874; Tue, 28 May 2024 14:43:36 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3yc50py1ks-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:36 +0000 Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44SEhW7v035350; Tue, 28 May 2024 14:43:35 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3yc50py1g5-4; Tue, 28 May 2024 14:43:35 +0000 From: Aruna Ramakrishna To: linux-kernel@vger.kernel.org Cc: x86@kernel.org, dave.hansen@linux.intel.com, tglx@linutronix.de, mingo@kernel.org, keith.lucas@oracle.com, aruna.ramakrishna@oracle.com Subject: [PATCH v4 3/5] x86/pkeys: Update PKRU to enable minimally required pkeys before XSAVE Date: Tue, 28 May 2024 14:43:29 +0000 Message-Id: <20240528144331.2758104-4-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> References: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.12.28.16 definitions=2024-05-28_10,2024-05-28_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 spamscore=0 suspectscore=0 adultscore=0 phishscore=0 malwarescore=0 mlxlogscore=801 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405280111 X-Proofpoint-GUID: OFLcUnhIgVuZGPihZtmhrk3F3T4uZHW1 X-Proofpoint-ORIG-GUID: OFLcUnhIgVuZGPihZtmhrk3F3T4uZHW1 Content-Type: text/plain; charset="utf-8" If the alternate signal stack is protected by a different pkey than the current execution stack, copying xsave data to the sigaltstack will fail if its pkey is not enabled. Enable the extra pkey needed, before xsave, so that the signal handler accessibility is not dictated by the PKRU value that the thread sets up. But this updated PKRU value is also pushed onto the sigframe, so overwrite that with the original, user-defined PKRU value so that the value restored from sigcontext does not have the ext= ra pkey enabled. Signed-off-by: Aruna Ramakrishna --- arch/x86/kernel/fpu/signal.c | 10 ++++++++-- arch/x86/kernel/signal.c | 10 +++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index b0b254b931fd..1065ab995305 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -168,8 +168,14 @@ static inline bool save_xstate_epilog(void __user *buf= , int ia32_frame, =20 static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, = u32 pkru) { - if (use_xsave()) - return xsave_to_user_sigframe(buf); + int err =3D 0; + + if (use_xsave()) { + err =3D xsave_to_user_sigframe(buf); + if (!err) + err =3D update_pkru_in_sigframe(buf, pkru); + return err; + } =20 if (use_fxsr()) return fxsave_to_user_sigframe((struct fxregs_state __user *) buf); diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 3fa66b2fe753..659faf076b48 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -243,8 +243,8 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) { struct fpu *fpu =3D ¤t->thread.fpu; - u32 pkru =3D read_pkru(); bool stepping, failed; + u32 pkru; =20 if (v8086_mode(regs)) save_v86_state((struct kernel_vm86_regs *) regs, VM86_SIGNAL); @@ -280,6 +280,8 @@ handle_signal(struct ksignal *ksig, struct pt_regs *reg= s) if (stepping) user_disable_single_step(current); =20 + /* Update PKRU to enable access to the alternate signal stack. */ + pkru =3D sig_prepare_pkru(); failed =3D (setup_rt_frame(ksig, regs, pkru) < 0); if (!failed) { /* @@ -297,6 +299,12 @@ handle_signal(struct ksignal *ksig, struct pt_regs *re= gs) * Ensure the signal handler starts with the new fpu state. */ fpu__clear_user_states(fpu); + } else { + /* + * Restore PKRU to the original, user-defined value; disable + * extra pkeys enabled for the alternate signal stack, if any. + */ + write_pkru(pkru); } signal_setup_done(failed, ksig, stepping); } --=20 2.39.3 From nobody Tue Dec 16 03:22:37 2025 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51414170829 for ; Tue, 28 May 2024 14:43:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.177.32 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907437; cv=none; b=oyssItOwF32GJBeScLx0xmJgnZOGgWiTiZTAzDq9fi8j49Lzt3sz7etp1XHgYu6VtT/kmD8ftionnpR1amT2/boci/+ZWZD0wfYsnfNB7ozr0VeYNetKDD/hzHiaUyVb2+2aT2M5fAqryXx9q6pay+bDxktKKcLHnf5LAYgDF0E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907437; c=relaxed/simple; bh=tlwUG6i2dN04+SFgN9SBdBQln0TBzFDCm4yq8WOlNIQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Ud/zIem33mjvsEFXrbUM3VyxmVxAGcX3MN+YKy9BzRL8oxdKiisCin1KeYlmysyMmZrKVKI5yxMu2Bq3MfwjrDEIzh60xbRBdcR0g+3QPtxfYUPHPhElkNdjq+CgOLB+GKSnT30tHh1Zo6OA2p24EjWDr50EjEicwTCPUs6vP7M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com; spf=pass smtp.mailfrom=oracle.com; arc=none smtp.client-ip=205.220.177.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oracle.com Received: from pps.filterd (m0333520.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44SBn1fD031927; Tue, 28 May 2024 14:43:51 GMT DKIM-Signature: =?UTF-8?Q?v=3D1;_a=3Drsa-sha256;_c=3Drelaxed/relaxed;_d=3Doracle.com;_h?= =?UTF-8?Q?=3Dcc:content-transfer-encoding:date:from:in-reply-to:message-i?= =?UTF-8?Q?d:mime-version:references:subject:to;_s=3Dcorp-2023-11-20;_bh?= =?UTF-8?Q?=3DKPsMX+2z7i40hslxQGSb/YJgYDxUNOarNeZ/dlWFyIc=3D;_b=3Dlju9reQT?= =?UTF-8?Q?cFHQ0dIZmRQwhF8PJeDvqSzT/JIYFGgXrVq4VvLFXIenPkxRrj0qWdvrGXVc_m1?= =?UTF-8?Q?DxJMi46GPSC2tpW900JNUjvXetxDBVFP1g/CUmNBKHmmAvC2/IRtRvw19BWpiSY?= =?UTF-8?Q?Ogb_aXcjtpvbsIJGY1uOk21FnsM0IBmvZq9FhRrsbkPQbiDdOs/ifB1GFVBHUCi?= =?UTF-8?Q?68RyLIUo8_LG7KWeqgoYESR/B4+N+Ch+DvyJXzX+FYPT1xi/fH7Ko3hrcQVjClq?= =?UTF-8?Q?tMJSw16wmZhbk7X_pS39Ilid3IS6UmTT2jZB+D0bEx9ew/DPr91avrV7kgBGrRh?= =?UTF-8?Q?UHkomkvZYfgDAopx+ycDb_Ww=3D=3D_?= Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3yb8g9mkbq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:50 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 44SDj2FL025795; Tue, 28 May 2024 14:43:37 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3yc50py1mu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:37 +0000 Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44SEhW7x035350; Tue, 28 May 2024 14:43:36 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3yc50py1g5-5; Tue, 28 May 2024 14:43:36 +0000 From: Aruna Ramakrishna To: linux-kernel@vger.kernel.org Cc: x86@kernel.org, dave.hansen@linux.intel.com, tglx@linutronix.de, mingo@kernel.org, keith.lucas@oracle.com, aruna.ramakrishna@oracle.com Subject: [PATCH v4 4/5] x86/pkeys: Restore altstack before sigcontext Date: Tue, 28 May 2024 14:43:30 +0000 Message-Id: <20240528144331.2758104-5-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> References: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.12.28.16 definitions=2024-05-28_10,2024-05-28_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 spamscore=0 suspectscore=0 adultscore=0 phishscore=0 malwarescore=0 mlxlogscore=723 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405280111 X-Proofpoint-GUID: U9QO9qC6kx28ti4fNPuB14nCVQUkjv9j X-Proofpoint-ORIG-GUID: U9QO9qC6kx28ti4fNPuB14nCVQUkjv9j Content-Type: text/plain; charset="utf-8" A process can disable access to the alternate signal stack and still expect signals to be delivered correctly. handle_signal() updates the PKRU value to enable access to the atlstack, and makes sure that the value on the sigframe is the user-defined PKRU value so that it is correctly restored. However, in sigreturn(), restore_altstack() needs read access to the alt stack. But the PKRU is already restored from the sigframe (in restore_sigcontext()) which will disable access to the alt stack, resulting in a SIGSEGV. Fix this by restoring altstack before restoring PKRU. Signed-off-by: Aruna Ramakrishna --- arch/x86/kernel/signal_32.c | 4 ++-- arch/x86/kernel/signal_64.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 68f2bfd7d6e7..c7a489f0d943 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c @@ -160,10 +160,10 @@ SYSCALL32_DEFINE0(rt_sigreturn) =20 set_current_blocked(&set); =20 - if (!ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext)) + if (restore_altstack32(&frame->uc.uc_stack)) goto badframe; =20 - if (restore_altstack32(&frame->uc.uc_stack)) + if (!ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; =20 return regs->ax; diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 6b189de005b5..2d053333fcf5 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@ -260,13 +260,13 @@ SYSCALL_DEFINE0(rt_sigreturn) =20 set_current_blocked(&set); =20 - if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags)) + if (restore_altstack(&frame->uc.uc_stack)) goto badframe; =20 - if (restore_signal_shadow_stack()) + if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags)) goto badframe; =20 - if (restore_altstack(&frame->uc.uc_stack)) + if (restore_signal_shadow_stack()) goto badframe; =20 return regs->ax; --=20 2.39.3 From nobody Tue Dec 16 03:22:37 2025 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F83D17164B for ; Tue, 28 May 2024 14:43:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.177.32 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907428; cv=none; b=ZDNZbmFOP2rALUTsGhkS4et/qKqxNBPDE7Q+wDaQVtnLv//JY2HHuGadcDIxh6/PciIL8l1R/gvr0YnSC6dYz7K3SS42YZahcKMaHLY7LfDy1/KX8Q4TxzniGKL0grc2EsA9bAB3kTzmW934GF2EIG2jt9iwYjLcZJ+TQevZCt8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716907428; c=relaxed/simple; bh=AUR+iHLSJz7WIunMyEoTeS9mQ7LXiUsbjhruGQV4tvA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=I07StLFnKZZ3do8BZ+n3liemPkUvK3pSpR/htScv0UOB0OaCgBeLTclF9Bj4Am8MRFLRu0gwyfY+tnhUBYl/xY1Pkhzqwx7iQdvsjqbEjfIns/0DlIH/jqYWmcaAVnZNysxKxeS9AiCsWi/uQfAY3pVRHi0LSb7LYbJ1yFAdkvU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com; spf=pass smtp.mailfrom=oracle.com; arc=none smtp.client-ip=205.220.177.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=oracle.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oracle.com Received: from pps.filterd (m0246630.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44SBnWf9020052; Tue, 28 May 2024 14:43:40 GMT DKIM-Signature: =?UTF-8?Q?v=3D1;_a=3Drsa-sha256;_c=3Drelaxed/relaxed;_d=3Doracle.com;_h?= =?UTF-8?Q?=3Dcc:content-transfer-encoding:date:from:in-reply-to:message-i?= =?UTF-8?Q?d:mime-version:references:subject:to;_s=3Dcorp-2023-11-20;_bh?= =?UTF-8?Q?=3DeluNYeGl4O6XY2ECjLhF19aKMqY+wnGu0PSE4LuplXc=3D;_b=3DKRCohi+p?= =?UTF-8?Q?qMkGoD89dky/BiXewf7htX8jYPanDyDXoBeDYtTZFOo2Ehjz46LeG/0de7RW_kG?= =?UTF-8?Q?bxiSv8bx89YAurEObv+NUxWUiVh7Z13Z2BtuQOy4geMr624pRlQV/QlVYYY8Z5U?= =?UTF-8?Q?m5f_m3+Btj5Q1M89RAe/x2DHZCEmdR3ex6Xolz455Nt03XMrbs2JKii3tA7hdy7?= =?UTF-8?Q?DZHLz39ge_1SNwU1bzS5qUxXn8s8HrrKRHjKvCFLBOLh72XnpPU9Z8yfKmfjI2k?= =?UTF-8?Q?lwABTJ4MwW65Csn_joPVBHLqlkNlerz7RfRleyU0ZZhrCC6bSkUwEg57R2sdZx1?= =?UTF-8?Q?c0udZAZ6u7Y8Jbk4JZnjz_Pg=3D=3D_?= Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3yb8j84esb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:39 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 44SDlPS6025792; Tue, 28 May 2024 14:43:38 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3yc50py1p2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 28 May 2024 14:43:38 +0000 Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44SEhW81035350; Tue, 28 May 2024 14:43:38 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3yc50py1g5-6; Tue, 28 May 2024 14:43:37 +0000 From: Aruna Ramakrishna To: linux-kernel@vger.kernel.org Cc: x86@kernel.org, dave.hansen@linux.intel.com, tglx@linutronix.de, mingo@kernel.org, keith.lucas@oracle.com, aruna.ramakrishna@oracle.com Subject: [PATCH v4 5/5] selftests/mm: Add new testcases for pkeys Date: Tue, 28 May 2024 14:43:31 +0000 Message-Id: <20240528144331.2758104-6-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> References: <20240528144331.2758104-1-aruna.ramakrishna@oracle.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.12.28.16 definitions=2024-05-28_10,2024-05-28_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 spamscore=0 suspectscore=0 adultscore=0 phishscore=0 malwarescore=0 mlxlogscore=999 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405280111 X-Proofpoint-ORIG-GUID: I7OxgCNN7PT_qDPuTDr_JNEptap_ALnB X-Proofpoint-GUID: I7OxgCNN7PT_qDPuTDr_JNEptap_ALnB Content-Type: text/plain; charset="utf-8" From: Keith Lucas This commit adds a few new tests to exercise the signal handler flow, especially with pkey 0 disabled. [ Aruna: Adapted to upstream ] Signed-off-by: Keith Lucas Signed-off-by: Aruna Ramakrishna --- tools/testing/selftests/mm/Makefile | 5 +- tools/testing/selftests/mm/pkey-helpers.h | 11 +- .../selftests/mm/pkey_sighandler_tests.c | 480 ++++++++++++++++++ tools/testing/selftests/mm/protection_keys.c | 10 - 4 files changed, 494 insertions(+), 12 deletions(-) create mode 100644 tools/testing/selftests/mm/pkey_sighandler_tests.c diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 410495e0a611..1bb95960d28b 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -2,6 +2,7 @@ # Makefile for mm selftests =20 LOCAL_HDRS +=3D $(selfdir)/mm/local_config.h $(top_srcdir)/mm/gup_test.h +LINUX_TOOL_INCLUDE =3D $(top_srcdir)/tools/include =20 include local_config.mk =20 @@ -32,7 +33,7 @@ endif # LDLIBS. MAKEFLAGS +=3D --no-builtin-rules =20 -CFLAGS =3D -Wall -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) +CFLAGS =3D -Wall -I $(top_srcdir) $(EXTRA_CFLAGS) -I$(LINUX_TOOL_INCLUDE) = $(KHDR_INCLUDES) LDLIBS =3D -lrt -lpthread -lm =20 TEST_GEN_FILES =3D cow @@ -82,6 +83,7 @@ CAN_BUILD_X86_64 :=3D $(shell ./../x86/check_cc.sh "$(CC)= " ../x86/trivial_64bit_pr CAN_BUILD_WITH_NOPIE :=3D $(shell ./../x86/check_cc.sh "$(CC)" ../x86/triv= ial_program.c -no-pie) =20 VMTARGETS :=3D protection_keys +VMTARGETS :=3D pkey_sighandler_tests BINARIES_32 :=3D $(VMTARGETS:%=3D%_32) BINARIES_64 :=3D $(VMTARGETS:%=3D%_64) =20 @@ -100,6 +102,7 @@ else =20 ifneq (,$(findstring $(ARCH),powerpc)) TEST_GEN_FILES +=3D protection_keys +TEST_GEN_FILES +=3D pkey_sighandler_tests endif =20 endif diff --git a/tools/testing/selftests/mm/pkey-helpers.h b/tools/testing/self= tests/mm/pkey-helpers.h index 1af3156a9db8..2b1189c27167 100644 --- a/tools/testing/selftests/mm/pkey-helpers.h +++ b/tools/testing/selftests/mm/pkey-helpers.h @@ -12,6 +12,7 @@ #include #include #include +#include =20 #include "../kselftest.h" =20 @@ -79,7 +80,15 @@ extern void abort_hooks(void); } \ } while (0) =20 -__attribute__((noinline)) int read_ptr(int *ptr); +noinline int read_ptr(int *ptr) +{ + /* + * Keep GCC from optimizing this away somehow + */ + barrier(); + return *ptr; +} + void expected_pkey_fault(int pkey); int sys_pkey_alloc(unsigned long flags, unsigned long init_val); int sys_pkey_free(unsigned long pkey); diff --git a/tools/testing/selftests/mm/pkey_sighandler_tests.c b/tools/tes= ting/selftests/mm/pkey_sighandler_tests.c new file mode 100644 index 000000000000..8a8dc284b40d --- /dev/null +++ b/tools/testing/selftests/mm/pkey_sighandler_tests.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tests Memory Protection Keys (see Documentation/core-api/protection-key= s.rst) + * + * The testcases in this file exercise various flows related to signal han= dling, + * using an alternate signal stack, with the default pkey (pkey 0) disable= d. + * + * Compile with: + * gcc -mxsave -o pkey_sighandler_tests -O2 -g -std=3Dgnu99 -pthread = -Wall pkey_sighandler_tests.c -I../../../../tools/include -lrt -ldl -lm + * gcc -mxsave -m32 -o pkey_sighandler_tests -O2 -g -std=3Dgnu99 -pthread = -Wall pkey_sighandler_tests.c -I../../../../tools/include -lrt -ldl -lm + */ +#define _GNU_SOURCE +#define __SANE_USERSPACE_TYPES__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkey-helpers.h" + +#define STACK_SIZE PTHREAD_STACK_MIN + +void expected_pkey_fault(int pkey) {} + +pthread_mutex_t mutex =3D PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond =3D PTHREAD_COND_INITIALIZER; +siginfo_t siginfo =3D {0}; + +/* + * We need to use inline assembly instead of glibc's syscall because glibc= 's + * syscall will attempt to access the PLT in order to call a library funct= ion + * which is protected by MPK 0 which we don't have access to. + */ +static inline __always_inline +long syscall_raw(long n, long a1, long a2, long a3, long a4, long a5, long= a6) +{ + unsigned long ret; +#ifdef __x86_64__ + register long r10 asm("r10") =3D a4; + register long r8 asm("r8") =3D a5; + register long r9 asm("r9") =3D a6; + asm volatile ("syscall" + : "=3Da"(ret) + : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9) + : "rcx", "r11", "memory"); +#elif defined __i386__ + asm volatile ("int $0x80" + : "=3Da"(ret) + : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) + : "memory"); +#endif + return ret; +} + +static void sigsegv_handler(int signo, siginfo_t *info, void *ucontext) +{ + pthread_mutex_lock(&mutex); + + memcpy(&siginfo, info, sizeof(siginfo_t)); + + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + + syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0); +} + +static void sigusr1_handler(int signo, siginfo_t *info, void *ucontext) +{ + pthread_mutex_lock(&mutex); + + memcpy(&siginfo, info, sizeof(siginfo_t)); + + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); +} + +static void sigusr2_handler(int signo, siginfo_t *info, void *ucontext) +{ + /* + * pkru should be the init_pkru value which enabled MPK 0 so + * we can use library functions. + */ + printf("%s invoked.\n", __func__); +} + +static void raise_sigusr2(void) +{ + pid_t tid =3D 0; + + tid =3D syscall_raw(SYS_gettid, 0, 0, 0, 0, 0, 0); + + syscall_raw(SYS_tkill, tid, SIGUSR2, 0, 0, 0, 0); + + /* + * We should return from the signal handler here and be able to + * return to the interrupted thread. + */ +} + +static void *thread_segv_with_pkey0_disabled(void *ptr) +{ + /* Disable MPK 0 (and all others too) */ + __write_pkey_reg(0x55555555); + + /* Segfault (with SEGV_MAPERR) */ + *(int *) (0x1) =3D 1; + return NULL; +} + +static void *thread_segv_pkuerr_stack(void *ptr) +{ + /* Disable MPK 0 (and all others too) */ + __write_pkey_reg(0x55555555); + + /* After we disable MPK 0, we can't access the stack to return */ + return NULL; +} + +static void *thread_segv_maperr_ptr(void *ptr) +{ + stack_t *stack =3D ptr; + int *bad =3D (int *)1; + + /* + * Setup alternate signal stack, which should be pkey_mprotect()ed by + * MPK 0. The thread's stack cannot be used for signals because it is + * not accessible by the default init_pkru value of 0x55555554. + */ + syscall_raw(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0); + + /* Disable MPK 0. Only MPK 1 is enabled. */ + __write_pkey_reg(0x55555551); + + /* Segfault */ + *bad =3D 1; + syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0); + return NULL; +} + +/* + * Verify that the sigsegv handler is invoked when pkey 0 is disabled. + * Note that the new thread stack and the alternate signal stack is + * protected by MPK 0. + */ +static void test_sigsegv_handler_with_pkey0_disabled(void) +{ + struct sigaction sa; + pthread_attr_t attr; + pthread_t thr; + + sa.sa_flags =3D SA_SIGINFO; + + sa.sa_sigaction =3D sigsegv_handler; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGSEGV, &sa, NULL) =3D=3D -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + memset(&siginfo, 0, sizeof(siginfo)); + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + pthread_create(&thr, &attr, thread_segv_with_pkey0_disabled, NULL); + + pthread_mutex_lock(&mutex); + while (siginfo.si_signo =3D=3D 0) + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + + ksft_test_result(siginfo.si_signo =3D=3D SIGSEGV && + siginfo.si_code =3D=3D SEGV_MAPERR && + siginfo.si_addr =3D=3D (void *)1, + "%s\n", __func__); +} + +/* + * Verify that the sigsegv handler is invoked when pkey 0 is disabled. + * Note that the new thread stack and the alternate signal stack is + * protected by MPK 0, which renders them inaccessible when MPK 0 + * is disabled. So just the return from the thread should cause a + * segfault with SEGV_PKUERR. + */ +static void test_sigsegv_handler_cannot_access_stack(void) +{ + struct sigaction sa; + pthread_attr_t attr; + pthread_t thr; + + sa.sa_flags =3D SA_SIGINFO; + + sa.sa_sigaction =3D sigsegv_handler; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGSEGV, &sa, NULL) =3D=3D -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + memset(&siginfo, 0, sizeof(siginfo)); + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + pthread_create(&thr, &attr, thread_segv_pkuerr_stack, NULL); + + pthread_mutex_lock(&mutex); + while (siginfo.si_signo =3D=3D 0) + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + + ksft_test_result(siginfo.si_signo =3D=3D SIGSEGV && + siginfo.si_code =3D=3D SEGV_PKUERR, + "%s\n", __func__); +} + +/* + * Verify that the sigsegv handler that uses an alternate signal stack + * is correctly invoked for a thread which uses a non-zero MPK to protect + * its own stack, and disables all other MPKs (including 0). + */ +static void test_sigsegv_handler_with_different_pkey_for_stack(void) +{ + struct sigaction sa; + static stack_t sigstack; + void *stack; + int pkey; + int parent_pid =3D 0; + int child_pid =3D 0; + + sa.sa_flags =3D SA_SIGINFO | SA_ONSTACK; + + sa.sa_sigaction =3D sigsegv_handler; + + sigemptyset(&sa.sa_mask); + if (sigaction(SIGSEGV, &sa, NULL) =3D=3D -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + stack =3D mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + assert(stack !=3D MAP_FAILED); + + /* Allow access to MPK 0 and MPK 1 */ + __write_pkey_reg(0x55555550); + + /* Protect the new stack with MPK 1 */ + pkey =3D pkey_alloc(0, 0); + pkey_mprotect(stack, STACK_SIZE, PROT_READ | PROT_WRITE, pkey); + + /* Set up alternate signal stack that will use the default MPK */ + sigstack.ss_sp =3D mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + sigstack.ss_flags =3D 0; + sigstack.ss_size =3D STACK_SIZE; + + memset(&siginfo, 0, sizeof(siginfo)); + + /* Use clone to avoid newer glibcs using rseq on new threads */ + long ret =3D syscall_raw(SYS_clone, + CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | + CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | + CLONE_DETACHED, + (long) ((char *)(stack) + STACK_SIZE), + (long) &parent_pid, + (long) &child_pid, 0, 0); + + if (ret < 0) { + errno =3D -ret; + perror("clone"); + } else if (ret =3D=3D 0) { + thread_segv_maperr_ptr(&sigstack); + syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0); + } + + pthread_mutex_lock(&mutex); + while (siginfo.si_signo =3D=3D 0) + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + + ksft_test_result(siginfo.si_signo =3D=3D SIGSEGV && + siginfo.si_code =3D=3D SEGV_MAPERR && + siginfo.si_addr =3D=3D (void *)1, + "%s\n", __func__); +} + +/* + * Verify that the PKRU value set by the application is correctly + * restored upon return from signal handling. + */ +static void test_pkru_preserved_after_sigusr1(void) +{ + struct sigaction sa; + unsigned long pkru =3D 0x45454544; + + sa.sa_flags =3D SA_SIGINFO; + + sa.sa_sigaction =3D sigusr1_handler; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGUSR1, &sa, NULL) =3D=3D -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + memset(&siginfo, 0, sizeof(siginfo)); + + __write_pkey_reg(pkru); + + raise(SIGUSR1); + + pthread_mutex_lock(&mutex); + while (siginfo.si_signo =3D=3D 0) + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + + /* Ensure the pkru value is the same after returning from signal. */ + ksft_test_result(pkru =3D=3D __read_pkey_reg() && + siginfo.si_signo =3D=3D SIGUSR1, + "%s\n", __func__); +} + +static noinline void *thread_sigusr2_self(void *ptr) +{ + /* + * A const char array like "Resuming after SIGUSR2" won't be stored on + * the stack and the code could access it via an offset from the program + * counter. This makes sure it's on the function's stack frame + * so we know where it is even when the code is copied. + */ + char str[] =3D {'R', 'e', 's', 'u', 'm', 'i', 'n', 'g', ' ', + 'a', 'f', 't', 'e', 'r', ' ', + 'S', 'I', 'G', 'U', 'S', 'R', '2', + '.', '.', '.', '\n', '\0'}; + stack_t *stack =3D ptr; + + /* + * Setup alternate signal stack, which should be pkey_mprotect()ed by + * MPK 0. The thread's stack cannot be used for signals because it is + * not accessible by the default init_pkru value of 0x55555554. + */ + syscall(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0); + + /* Disable MPK 0. Only MPK 2 is enabled. */ + __write_pkey_reg(0x55555545); + + raise_sigusr2(); + + /* Do something, to show the thread resumed execution after the signal */ + syscall_raw(SYS_write, 1, (long) str, sizeof(str) - 1, 0, 0, 0); + + /* + * We can't return to test_pkru_sigreturn because it + * will attempt to use a %rbp value which is on the stack + * of the main thread. + */ + syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0); + return NULL; +} + +/* + * Verify that sigreturn is able to restore altstack even if the thread had + * disabled pkey 0. + */ +static void test_pkru_sigreturn(void) +{ + struct sigaction sa =3D {0}; + static stack_t sigstack; + void *stack; + int pkey; + int parent_pid =3D 0; + int child_pid =3D 0; + + sa.sa_handler =3D SIG_DFL; + sa.sa_flags =3D 0; + sigemptyset(&sa.sa_mask); + + /* + * For this testcase, we do not want to handle SIGSEGV. Reset handler + * to default so that the application can crash if it receives SIGSEGV. + */ + if (sigaction(SIGSEGV, &sa, NULL) =3D=3D -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + sa.sa_flags =3D SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction =3D sigusr2_handler; + sigemptyset(&sa.sa_mask); + + if (sigaction(SIGUSR2, &sa, NULL) =3D=3D -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + stack =3D mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + assert(stack !=3D MAP_FAILED); + + /* + * Allow access to MPK 0 and MPK 2. The child thread (to be created + * later in this flow) will have its stack protected by MPK 2, whereas + * the current thread's stack is protected by the default MPK 0. Hence + * both need to be enabled. + */ + __write_pkey_reg(0x55555544); + + /* Protect the stack with MPK 2 */ + pkey =3D pkey_alloc(0, 0); + pkey_mprotect(stack, STACK_SIZE, PROT_READ | PROT_WRITE, pkey); + + /* Set up alternate signal stack that will use the default MPK */ + sigstack.ss_sp =3D mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + sigstack.ss_flags =3D 0; + sigstack.ss_size =3D STACK_SIZE; + + /* Use clone to avoid newer glibcs using rseq on new threads */ + long ret =3D syscall_raw(SYS_clone, + CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | + CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | + CLONE_DETACHED, + (long) ((char *)(stack) + STACK_SIZE), + (long) &parent_pid, + (long) &child_pid, 0, 0); + + if (ret < 0) { + errno =3D -ret; + perror("clone"); + } else if (ret =3D=3D 0) { + thread_sigusr2_self(&sigstack); + syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0); + } + + child_pid =3D ret; + /* Check that thread exited */ + do { + sched_yield(); + ret =3D syscall_raw(SYS_tkill, child_pid, 0, 0, 0, 0, 0); + } while (ret !=3D -ESRCH && ret !=3D -EINVAL); + + ksft_test_result_pass("%s\n", __func__); +} + +void (*pkey_tests[])(void) =3D { + test_sigsegv_handler_with_pkey0_disabled, + test_sigsegv_handler_cannot_access_stack, + test_sigsegv_handler_with_different_pkey_for_stack, + test_pkru_preserved_after_sigusr1, + test_pkru_sigreturn +}; + +int main(int argc, char *argv[]) +{ + int i; + + ksft_print_header(); + ksft_set_plan(ARRAY_SIZE(pkey_tests)); + + for (i =3D 0; i < ARRAY_SIZE(pkey_tests); i++) + (*pkey_tests[i])(); + + ksft_finished(); + return 0; +} diff --git a/tools/testing/selftests/mm/protection_keys.c b/tools/testing/s= elftests/mm/protection_keys.c index 48dc151f8fca..2af344e55d37 100644 --- a/tools/testing/selftests/mm/protection_keys.c +++ b/tools/testing/selftests/mm/protection_keys.c @@ -950,16 +950,6 @@ void close_test_fds(void) nr_test_fds =3D 0; } =20 -#define barrier() __asm__ __volatile__("": : :"memory") -__attribute__((noinline)) int read_ptr(int *ptr) -{ - /* - * Keep GCC from optimizing this away somehow - */ - barrier(); - return *ptr; -} - void test_pkey_alloc_free_attach_pkey0(int *ptr, u16 pkey) { int i, err; --=20 2.39.3