From nobody Fri Dec 19 15:30:38 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 59CFC14E2F6 for ; Thu, 25 Apr 2024 18:05:56 +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=1714068358; cv=none; b=SGxEVs/DWFrwg5J7gpZm247Cba+ePSJpXa7zACza6qkvYOZ+RFOu3lriWDlXbYw+3J/7pq/jXKaBIFzl7hL8ZOMiKttnV75wkqaRCfTpiGkwbUAuwYQnfqH8wRseUu/WMRFZbeFOYp69US9OM0GPYGiXttVlItWJTX3ppesXbeg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714068358; c=relaxed/simple; bh=8rq6Adds/zpBLD1a9WAfrh3DcH8eENB9USB0foTiplM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=L1t0n8tAV1E42ApoZYUaywSuVEhircpvu6Q9WQbqUCKaESRJCCmdzCjiVegHPV/nSWZRZ3vVIGBzmbWHobBrMRvFrcLWR4PQhuZg0AJCtpTjBAqy4MpNnV9WDARWAbjUrzCiwFvNa/AccJzkFKtRd4K4Xue2fxNCGuXWffbYtDU= 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; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b=KFWodhMQ; 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="KFWodhMQ" 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 43PHOMAp010734; Thu, 25 Apr 2024 18:05:47 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=corp-2023-11-20; bh=31XPIbpFXGej3w35FEErx3CUp5UQ8Coxsd7dySEPO6c=; b=KFWodhMQqkVehvT3K5bj+yo5fMCJKzLeBpdgB5ueLXwKxIbAbb70oZthlhtP73X8rC/b xff/c6J/Xis+QoFXwi8MfGu9O95JnB06CTfX6PQoR1qv5XNuSX8sZXcRzb39XPjW6u6J bp5naccqtx2cQmmHvwfZSs5EaknqK9HCGaSMxXGTNM7tti7TXuMQ4JClJ1uVnh2OwmKl IzzKZR3I5x583vF1c26/v2EGnbZEMvN15bMj43y3gTTD6QlFNxC3xZNZw6J0d7v2B/CZ iUeX8eqw8aEZFLzBUKtqkevZcIuSp+4ruKAgj3JU+ifU39BXIfa+r5U6i9glmxj1U+6g 5g== Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.appoci.oracle.com [138.1.37.129]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3xm68vmhmg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:47 +0000 Received: from pps.filterd (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 43PI0RPs001768; Thu, 25 Apr 2024 18:05:46 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3xm45be40c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:46 +0000 Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 43PI20Kf032785; Thu, 25 Apr 2024 18:05:46 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3xm45be3wd-2; Thu, 25 Apr 2024 18:05:45 +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 v3 1/4] x86/pkeys: Signal handling function interface changes to accept PKRU as a parameter Date: Thu, 25 Apr 2024 18:05:39 +0000 Message-Id: <20240425180542.1042933-2-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240425180542.1042933-1-aruna.ramakrishna@oracle.com> References: <20240425180542.1042933-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.1011,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-04-25_17,2024-04-25_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 phishscore=0 suspectscore=0 bulkscore=0 mlxlogscore=999 spamscore=0 malwarescore=0 mlxscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2404010000 definitions=main-2404250131 X-Proofpoint-GUID: 1IEvb9a_R5W-igl4s7TvPZ7xCT611Xs2 X-Proofpoint-ORIG-GUID: 1IEvb9a_R5W-igl4s7TvPZ7xCT611Xs2 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, this patchset does something like this: orig_pkru =3D rdpkru(); wrpkru(0); xsave_to_user_sigframe(); put_user(pkru_sigframe_addr, orig_pkru) This change is split over multiple patches. This patch adds pkru as an additional parameter that's passed 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. In a later patch, this pkru value will be written onto the sigframe, so that it is correctly restored from the sigcontext. Signed-off-by: Aruna Ramakrishna --- arch/x86/include/asm/fpu/signal.h | 3 ++- arch/x86/include/asm/sighandling.h | 10 +++++----- arch/x86/kernel/fpu/signal.c | 8 +++++--- arch/x86/kernel/signal.c | 18 ++++++++++-------- arch/x86/kernel/signal_32.c | 8 ++++---- arch/x86/kernel/signal_64.c | 9 +++++---- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/s= ignal.h index 611fa41711af..deaa81f44c2a 100644 --- a/arch/x86/include/asm/fpu/signal.h +++ b/arch/x86/include/asm/fpu/signal.h @@ -29,7 +29,8 @@ 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..7654f368accd 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -156,7 +156,8 @@ 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 +186,8 @@ 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 +230,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..d1c84b7f6852 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,8 @@ 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 +207,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,13 +215,13 @@ 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 @@ -229,6 +230,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *reg= s) { bool stepping, failed; struct fpu *fpu =3D ¤t->thread.fpu; + u32 pkru =3D read_pkru(); =20 if (v8086_mode(regs)) save_v86_state((struct kernel_vm86_regs *) regs, VM86_SIGNAL); @@ -264,7 +266,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..b5c9535ff08b 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,8 @@ 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 +301,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 +312,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 Fri Dec 19 15:30:38 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 5013215099C for ; Thu, 25 Apr 2024 18:06:00 +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=1714068361; cv=none; b=I32bX+25dw7Wfnaxy2BN3dxNVshfnC7/K6KI6iuF8MYeFB/WsqCNeG/tPNEd2rDNd8SbmSR5pisxH2k0humdUDIMps8wLkGmqBd10iN+O1auvsxqtncanpFkbDlqeJE3zP8kogxiU1RuylfmcFvDzpYIbn76JeWGinVi13fRmq0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714068361; c=relaxed/simple; bh=K+0J6Bj04zWUE89Vk4cjO0gJ0H8x5e4z1TPRbDqnSTE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gW2YKCkGfF8HM4E8cBRslKm6Mi3yDFhfBvFMDvfLZW8WvKy1Wqlzkd82YmynW2JeS4eiy3fsN9RDedtCC5OWkPh6eaBrqANsg5jBXUh8Mbf/PhmLnCGi7JQrhQXjlHMwmtqvH/4B0HMnFCIEU5BGzX8X+OjOa9JMxjphN7y1UYI= 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; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b=O8JaT3VO; 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="O8JaT3VO" Received: from pps.filterd (m0246631.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 43PHNso6016494; Thu, 25 Apr 2024 18:05:49 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=corp-2023-11-20; bh=bciJ3qiYRM4s0xTWQzH4AoRR6lKqwLH9mUMl9jleEC0=; b=O8JaT3VO87RUURXdZRHkJ+L/vCtr3Pl/w6dH/G3fIyBm2WYG8J5N8iC6nVb6QkeipBtm 2YCH/Zl5Ndk+5lbH03d+4ugHQNvDiJrcoV8hwQH6Bc1degHBZY+tsgCTU+L5u/ss41PQ ayJ91t43b8hAU4e6GzHD0IXRf5y0mbiqwrdyT3OZ8pDEHo7xS3Wva1ZmqGWfG4qHLEXE Y9nQTGEcKUUZv92OgvuRssagx/1rTyyEumbgjIvH5DeqXVNXxgnHMfwbWJjVWVC75vwA A3KjyxI/5/t95bwLYUk0a6Op0jM6YWxZiIDezEjfhDfgCik8tAk7ootfsMlWqnwnyRkO OQ== Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.appoci.oracle.com [138.1.37.129]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3xm4g4m1eu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:48 +0000 Received: from pps.filterd (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 43PH6prR001805; Thu, 25 Apr 2024 18:05:47 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3xm45be415-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:47 +0000 Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 43PI20Kh032785; Thu, 25 Apr 2024 18:05:47 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3xm45be3wd-3; Thu, 25 Apr 2024 18:05:47 +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 v3 2/4] x86/pkeys: Add helper functions to update PKRU on sigframe Date: Thu, 25 Apr 2024 18:05:40 +0000 Message-Id: <20240425180542.1042933-3-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240425180542.1042933-1-aruna.ramakrishna@oracle.com> References: <20240425180542.1042933-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.1011,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-04-25_17,2024-04-25_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 phishscore=0 suspectscore=0 bulkscore=0 mlxlogscore=999 spamscore=0 malwarescore=0 mlxscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2404010000 definitions=main-2404250131 X-Proofpoint-GUID: Fynm98EyF-LKuFz2FEJC2tvbUf96H4-Z X-Proofpoint-ORIG-GUID: Fynm98EyF-LKuFz2FEJC2tvbUf96H4-Z Content-Type: text/plain; charset="utf-8" This patch adds 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 | 26 ++++++++++++++++++++++++++ arch/x86/kernel/fpu/xstate.c | 13 +++++++++++++ arch/x86/kernel/fpu/xstate.h | 1 + arch/x86/kernel/signal.c | 12 ++++++++++++ 4 files changed, 52 insertions(+) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 7654f368accd..dce84cce7cf8 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -63,6 +63,32 @@ 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 signal frame. + */ +static inline int +__update_pkru_in_sigframe(struct xregs_state __user *buf, u32 pkru) +{ + int err =3D -EFAULT; + struct _fpx_sw_bytes fx_sw; + struct pkru_state *pk =3D NULL; + + if (unlikely(!check_xstate_in_sigframe((void __user *) buf, &fx_sw))) + goto out; + + pk =3D get_xsave_addr_user(buf, XFEATURE_PKRU); + if (!pk || !user_write_access_begin(buf, sizeof(struct xregs_state))) + goto out; + unsafe_put_user(pkru, (unsigned int __user *) pk, uaccess_end); + + err =3D 0; +uaccess_end: + user_access_end(); +out: + return err; +} + /* * Signal frame handlers. */ diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 33a214b1a4ce..8395a3633709 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 state is. The xsave buffer should be in standard + * format, not compacted (e.g. user mode signal frames). + */ +void *get_xsave_addr_user(struct xregs_state __user *xsave, int xfeature_n= r) +{ + if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr))) + return NULL; + + return (void *)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..6511797940ad 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 *get_xsave_addr_user(struct xregs_state *xsave, int xfeature_n= r); =20 static inline u64 xfeatures_mask_supervisor(void) { diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index d1c84b7f6852..75dfd05c59aa 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -225,6 +225,18 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *r= egs, u32 pkru) } } =20 +/* + * Enable all pkeys to ensure that both the current stack and the alternate + * signal stack are always writeable. + */ +static inline u32 sig_prepare_pkru(void) +{ + u32 orig_pkru =3D read_pkru(); + + write_pkru(0); + return orig_pkru; +} + static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) { --=20 2.39.3 From nobody Fri Dec 19 15:30:38 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 501CF1509A2 for ; Thu, 25 Apr 2024 18:06:00 +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=1714068361; cv=none; b=RbL91BcQCqBfxPaewFrsKrKTFlqOTbZCniXj9Qf1p5QyUwXByy5q9sGFNRmOXXBizhWk0ltsgxeZK1YAtWbOzHdvGprPpovanI007fqpjra+h2c+6NuWoN5WmpTLLpDHNI+waAWH/emQTsvaEXvf9nWgpgdXmZemlF3KuZ9cBxo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714068361; c=relaxed/simple; bh=cI7gssY7RK5sFBcqYPd69se9pxreozcJ57b2DuII1KI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=oYAolIKe3PbSfWFwFB/ImdpLa+7GfM6J8+J2Dv8Kt3PhwcCQFTFQ+1wYKDvM+zVqJoAoeBYf0QL9wML/DeQW+/sIg9LAfcZmQ/jgP68yeA0yXhbTR7LxJ7wrazt9fCEXL9V66sjOZ7pMMbhufN8Viq2UZnN2oj0y/BmrxIa977g= 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; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b=YKDhNvoH; 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="YKDhNvoH" 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 43PHNxlJ024243; Thu, 25 Apr 2024 18:05:50 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=corp-2023-11-20; bh=PpOUtB30mkU/WhCWnJO885CVzo2dXyXZaqQ4tqSiGwI=; b=YKDhNvoHpKYAErNlmQk2logYk3ypjlQqNq3+B8s0SA0SHZ/YVKzljLac3pjO4zVFvnmU dAT6PAfzsk0vSsE7DFZA7iczqzGPx5DsWRG4PJIMWDuMyfNHDHVYptYC9zF6abvqLoFR QB3S4Wy8RGDUJB985WjpyzDYS+2bMBsxchGwS2DrBuLP+hseSWrgooYzlStXRZnnab4F wOsPfETdnA8wRaa11Dg8LoKp/NdKu2tazzaLt5+EWyPdLHdEbVnZy919k7Rxbh/7aL8C 17hVyxfT8CnVCbJ9ZeWB+Yf9/Sl4KA/YlQ87pCh3taiTx4cwbP/G04+bfmeViVHyVDup 6Q== Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.appoci.oracle.com [138.1.37.129]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3xm5re44gu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:50 +0000 Received: from pps.filterd (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 43PGTbR6001812; Thu, 25 Apr 2024 18:05:49 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3xm45be425-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:49 +0000 Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 43PI20Kj032785; Thu, 25 Apr 2024 18:05:48 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3xm45be3wd-4; Thu, 25 Apr 2024 18:05:48 +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 v3 3/4] x86/pkeys: Update PKRU to enable all pkeys before XSAVE Date: Thu, 25 Apr 2024 18:05:41 +0000 Message-Id: <20240425180542.1042933-4-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240425180542.1042933-1-aruna.ramakrishna@oracle.com> References: <20240425180542.1042933-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.1011,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-04-25_17,2024-04-25_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 phishscore=0 suspectscore=0 bulkscore=0 mlxlogscore=999 spamscore=0 malwarescore=0 mlxscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2404010000 definitions=main-2404250131 X-Proofpoint-ORIG-GUID: E0CnQJjba1e4Np_Llegy2PTRtSuUzgLD X-Proofpoint-GUID: E0CnQJjba1e4Np_Llegy2PTRtSuUzgLD 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 altsigstack will fail if its pkey is not enabled. This commit enables all pkeys before xsave, so that the signal handler accessibility is not dictated by the PKRU value that the thread sets up. It then writes the original PKRU value onto the sigframe so that it's restored correctly from sigcontext. Signed-off-by: Aruna Ramakrishna --- arch/x86/kernel/fpu/signal.c | 11 +++++++++-- arch/x86/kernel/signal.c | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index dce84cce7cf8..5d52c7fde43b 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -185,8 +185,15 @@ static inline bool save_xstate_epilog(void __user *buf= , int ia32_frame, 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 && cpu_feature_enabled(X86_FEATURE_OSPKE)) + err =3D __update_pkru_in_sigframe(buf, pkru); + return err; + } + if (use_fxsr()) return fxsave_to_user_sigframe((struct fxregs_state __user *) buf); else diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 75dfd05c59aa..c985bdfd855a 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -278,6 +278,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *reg= s) if (stepping) user_disable_single_step(current); =20 + pkru =3D sig_prepare_pkru(); failed =3D (setup_rt_frame(ksig, regs, pkru) < 0); if (!failed) { /* @@ -295,6 +296,8 @@ handle_signal(struct ksignal *ksig, struct pt_regs *reg= s) * Ensure the signal handler starts with the new fpu state. */ fpu__clear_user_states(fpu); + } else { + write_pkru(pkru); } signal_setup_done(failed, ksig, stepping); } --=20 2.39.3 From nobody Fri Dec 19 15:30:38 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 501801509A0 for ; Thu, 25 Apr 2024 18:06:00 +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=1714068365; cv=none; b=VtzXV7B6uPHY2PhghBi49OQksIx0Inm8ElatFBhCByUfZlfVHT0Ac5FPdR78pXKa8NeGhCn4nTCIgDtMB6BC5+yCIiItNfyp8beEvm2SHS0HRWliJXQoE044s1aaPVceFMHRlQ45P8jhsiplk3TJZu9v9mFmastj5+5zM6xBisM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714068365; c=relaxed/simple; bh=ScQJ619y+GLs1OSVTuQky0J/AgX81URn1hBDRJGl+6Q=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=oj6Vd8MEghLSkfzbkNP2zKqiIxGUiTKtSlcrSAZ43vtJUI0yAjaA3eTI36dY/KoMfsczxr8u5DGc5GNzAt0zUkTDOXQ8Pfonun88nWuU0b0qzlU45kGAgBEvzAVk0ZxZlwM2XQ0c14hjvIzunskXspfgOIzBQ9fhXHlsl6j+3ak= 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; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b=HpO5+MvI; 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="HpO5+MvI" Received: from pps.filterd (m0246631.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 43PHNso7016494; Thu, 25 Apr 2024 18:05:52 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=corp-2023-11-20; bh=zhNxV+WkimC8M1gbMsCHT8yixzJzj2YrCmtHjO4v/Co=; b=HpO5+MvI243AzogPMgypC63sshnglYSG0ec710GIog4Je+hn1wD4BVZ4wZ40FAAaVMTU 0auR4p3w5qJxvToaa9xbleEcLJsaXEfElNYPF8Dhbk3FhlqUKztNu5B2dbQKanSmSjcW 725tVZL8FW1zcAtSdSRSBGJywiiTeuxvyhumF0kSOTMxSTmaIERvrCkM/h2q5lL6K7OF aO9ZZ/uvH2JMfdsv5OoyDINEgnjYWkVxY3zH4TTUf/VVLvZTB7lF1Oqjmd1OetTaPq1Y SxeSDAVxaOwg3UFygeqH4M38P2BhJWoltOWjvLd9QyQ5FGMv6JiCMxZDZxO2d+t+Pxix fQ== Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.appoci.oracle.com [138.1.37.129]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3xm4g4m1ey-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:51 +0000 Received: from pps.filterd (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 43PGdxmH001947; Thu, 25 Apr 2024 18:05:50 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3xm45be433-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 25 Apr 2024 18:05:50 +0000 Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 43PI20Kl032785; Thu, 25 Apr 2024 18:05:49 GMT Received: from aruramak-dev.osdevelopmeniad.oraclevcn.com (aruramak-dev.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.155]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3xm45be3wd-5; Thu, 25 Apr 2024 18:05:49 +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 v3 4/4] selftests/mm: Add new testcases for pkeys Date: Thu, 25 Apr 2024 18:05:42 +0000 Message-Id: <20240425180542.1042933-5-aruna.ramakrishna@oracle.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240425180542.1042933-1-aruna.ramakrishna@oracle.com> References: <20240425180542.1042933-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.1011,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-04-25_17,2024-04-25_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 phishscore=0 suspectscore=0 bulkscore=0 mlxlogscore=999 spamscore=0 malwarescore=0 mlxscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2404010000 definitions=main-2404250131 X-Proofpoint-GUID: IOhGuhS5HPMIqiPCcNMsSQJZf_4h5EzS X-Proofpoint-ORIG-GUID: IOhGuhS5HPMIqiPCcNMsSQJZf_4h5EzS Content-Type: text/plain; charset="utf-8" This commit adds a few new tests to exercise the signal handler flow, especially with pkey 0 disabled. Signed-off-by: Keith Lucas Signed-off-by: Aruna Ramakrishna --- tools/testing/selftests/mm/Makefile | 2 + tools/testing/selftests/mm/pkey-helpers.h | 11 +- .../selftests/mm/pkey_sighandler_tests.c | 315 ++++++++++++++++++ tools/testing/selftests/mm/protection_keys.c | 10 - 4 files changed, 327 insertions(+), 11 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 eb5f39a2668b..2f90344ad11e 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -82,6 +82,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 +101,7 @@ else =20 ifneq (,$(findstring $(ARCH),ppc64)) 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..a0766e3d9ab6 100644 --- a/tools/testing/selftests/mm/pkey-helpers.h +++ b/tools/testing/selftests/mm/pkey-helpers.h @@ -79,7 +79,16 @@ extern void abort_hooks(void); } \ } while (0) =20 -__attribute__((noinline)) int read_ptr(int *ptr); +#define barrier() __asm__ __volatile__("": : :"memory") +__attribute__((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..eb4155859846 --- /dev/null +++ b/tools/testing/selftests/mm/pkey_sighandler_tests.c @@ -0,0 +1,315 @@ +#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" + +/* + * Compile with: + * gcc -mxsave -o pkey_sighandler_tests -O2 -g -std=3Dgnu99 -pthread = -Wall pkey_sighandler_tests.c -lrt -ldl -lm + */ + +#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}; + +static inline __attribute__((always_inline)) long +syscall_raw(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ + unsigned long ret; + 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"); + 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 *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; + + 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_t thr; + pthread_attr_t attr; + 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); + + assert(siginfo.si_signo =3D=3D SIGSEGV); + assert(siginfo.si_code =3D=3D SEGV_MAPERR); + assert(siginfo.si_addr =3D=3D (void *)1); + printf("%s passed!\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; + + 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_t thr; + pthread_attr_t attr; + 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); + + assert(siginfo.si_signo =3D=3D SIGSEGV); + assert(siginfo.si_code =3D=3D SEGV_PKUERR); + printf("%s passed!\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 parentPid =3D 0; + int childPid =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)&parentPid, + (long)&childPid, 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); + + assert(siginfo.si_signo =3D=3D SIGSEGV); + assert(siginfo.si_code =3D=3D SEGV_MAPERR); + assert(siginfo.si_addr =3D=3D (void *)1); + printf("%s passed!\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. */ + assert(pkru =3D=3D __read_pkey_reg()); + assert(siginfo.si_signo =3D=3D SIGUSR1); + printf("%s passed!\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, +}; + +int main(int argc, char *argv[]) +{ + size_t i; + + for (i =3D 0; i < sizeof(pkey_tests)/sizeof(pkey_tests[0]); i++) { + (*pkey_tests[i])(); + } + + printf("All pkey-signal-handling tests PASSED!\n"); + return 0; +} + diff --git a/tools/testing/selftests/mm/protection_keys.c b/tools/testing/s= elftests/mm/protection_keys.c index 374a308174d2..ec1e1d30ea6f 100644 --- a/tools/testing/selftests/mm/protection_keys.c +++ b/tools/testing/selftests/mm/protection_keys.c @@ -951,16 +951,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