[PATCH v3 3/4] x86/pkeys: Update PKRU to enable all pkeys before XSAVE

From: Aruna Ramakrishna
Date: Thu Apr 25 2024 - 14:06:28 EST


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 <aruna.ramakrishna@xxxxxxxxxx>
---
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 = 0;
+
+ if (use_xsave()) {
+ err = xsave_to_user_sigframe(buf);
+ if (!err && cpu_feature_enabled(X86_FEATURE_OSPKE))
+ err = __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 *regs)
if (stepping)
user_disable_single_step(current);

+ pkru = sig_prepare_pkru();
failed = (setup_rt_frame(ksig, regs, pkru) < 0);
if (!failed) {
/*
@@ -295,6 +296,8 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
* 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);
}
--
2.39.3