Skip to content

Commit 70044df

Browse files
arunarKAGA-KOKO
authored andcommitted
x86/pkeys: Update PKRU to enable all pkeys before XSAVE
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 in the PKRU register. It's unknown which pkey was used by the application for the altstack, so enable all PKEYS before XSAVE. But this updated PKRU value is also pushed onto the sigframe, which means the register value restored from sigcontext will be different from the user-defined one, which is incorrect. Fix that by overwriting the PKRU value on the sigframe with the original, user-defined PKRU. Signed-off-by: Aruna Ramakrishna <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 84ee6e8 commit 70044df

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

arch/x86/kernel/fpu/signal.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,15 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame,
168168

169169
static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, u32 pkru)
170170
{
171-
if (use_xsave())
172-
return xsave_to_user_sigframe(buf);
171+
int err = 0;
172+
173+
if (use_xsave()) {
174+
err = xsave_to_user_sigframe(buf);
175+
if (!err)
176+
err = update_pkru_in_sigframe(buf, pkru);
177+
return err;
178+
}
179+
173180
if (use_fxsr())
174181
return fxsave_to_user_sigframe((struct fxregs_state __user *) buf);
175182
else

arch/x86/kernel/signal.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
102102
unsigned long math_size = 0;
103103
unsigned long sp = regs->sp;
104104
unsigned long buf_fx = 0;
105-
u32 pkru = read_pkru();
105+
u32 pkru;
106106

107107
/* redzone */
108108
if (!ia32_frame)
@@ -157,9 +157,17 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
157157
return (void __user *)-1L;
158158
}
159159

160+
/* Update PKRU to enable access to the alternate signal stack. */
161+
pkru = sig_prepare_pkru();
160162
/* save i387 and extended state */
161-
if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size, pkru))
163+
if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size, pkru)) {
164+
/*
165+
* Restore PKRU to the original, user-defined value; disable
166+
* extra pkeys enabled for the alternate signal stack, if any.
167+
*/
168+
write_pkru(pkru);
162169
return (void __user *)-1L;
170+
}
163171

164172
return (void __user *)sp;
165173
}

0 commit comments

Comments
 (0)