Skip to content

Commit 4a804c4

Browse files
khueyhansendc
authored andcommitted
x86/fpu: Allow PKRU to be (once again) written by ptrace.
Move KVM's PKRU handling code in fpu_copy_uabi_to_guest_fpstate() to copy_uabi_to_xstate() so that it is shared with other APIs that write the XSTATE such as PTRACE_SETREGSET with NT_X86_XSTATE. This restores the pre-5.14 behavior of ptrace. The regression can be seen by running gdb and executing `p $pkru`, `set $pkru = 42`, and `p $pkru`. On affected kernels (5.14+) the write to the PKRU register (which gdb performs through ptrace) is ignored. [ dhansen: removed stable@ tag for now. The ABI was broken for long enough that this is not urgent material. Let's let it stew in tip for a few weeks before it's submitted to stable because there are so many ABIs potentially affected. ] Fixes: e84ba47 ("x86/fpu: Hook up PKRU into ptrace()") Signed-off-by: Kyle Huey <me@kylehuey.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Link: https://lore.kernel.org/all/20221115230932.7126-5-khuey%40kylehuey.com
1 parent 2c87767 commit 4a804c4

File tree

2 files changed

+21
-13
lines changed

2 files changed

+21
-13
lines changed

arch/x86/kernel/fpu/core.c

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,6 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
391391
{
392392
struct fpstate *kstate = gfpu->fpstate;
393393
const union fpregs_state *ustate = buf;
394-
struct pkru_state *xpkru;
395-
int ret;
396394

397395
if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) {
398396
if (ustate->xsave.header.xfeatures & ~XFEATURE_MASK_FPSSE)
@@ -406,16 +404,7 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
406404
if (ustate->xsave.header.xfeatures & ~xcr0)
407405
return -EINVAL;
408406

409-
ret = copy_uabi_from_kernel_to_xstate(kstate, ustate, vpkru);
410-
if (ret)
411-
return ret;
412-
413-
/* Retrieve PKRU if not in init state */
414-
if (kstate->regs.xsave.header.xfeatures & XFEATURE_MASK_PKRU) {
415-
xpkru = get_xsave_addr(&kstate->regs.xsave, XFEATURE_PKRU);
416-
*vpkru = xpkru->pkru;
417-
}
418-
return 0;
407+
return copy_uabi_from_kernel_to_xstate(kstate, ustate, vpkru);
419408
}
420409
EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate);
421410
#endif /* CONFIG_KVM */

arch/x86/kernel/fpu/xstate.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1205,10 +1205,22 @@ static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size,
12051205
* @fpstate: The fpstate buffer to copy to
12061206
* @kbuf: The UABI format buffer, if it comes from the kernel
12071207
* @ubuf: The UABI format buffer, if it comes from userspace
1208-
* @pkru: unused
1208+
* @pkru: The location to write the PKRU value to
12091209
*
12101210
* Converts from the UABI format into the kernel internal hardware
12111211
* dependent format.
1212+
*
1213+
* This function ultimately has three different callers with distinct PKRU
1214+
* behavior.
1215+
* 1. When called from sigreturn the PKRU register will be restored from
1216+
* @fpstate via an XRSTOR. Correctly copying the UABI format buffer to
1217+
* @fpstate is sufficient to cover this case, but the caller will also
1218+
* pass a pointer to the thread_struct's pkru field in @pkru and updating
1219+
* it is harmless.
1220+
* 2. When called from ptrace the PKRU register will be restored from the
1221+
* thread_struct's pkru field. A pointer to that is passed in @pkru.
1222+
* 3. When called from KVM the PKRU register will be restored from the vcpu's
1223+
* pkru field. A pointer to that is passed in @pkru.
12121224
*/
12131225
static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
12141226
const void __user *ubuf, u32 *pkru)
@@ -1260,6 +1272,13 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
12601272
}
12611273
}
12621274

1275+
if (hdr.xfeatures & XFEATURE_MASK_PKRU) {
1276+
struct pkru_state *xpkru;
1277+
1278+
xpkru = __raw_xsave_addr(xsave, XFEATURE_PKRU);
1279+
*pkru = xpkru->pkru;
1280+
}
1281+
12631282
/*
12641283
* The state that came in from userspace was user-state only.
12651284
* Mask all the user states out of 'xfeatures':

0 commit comments

Comments
 (0)