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: e84ba47e31
("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
This commit is contained in:
parent
2c87767c35
commit
4a804c4f83
|
@ -391,8 +391,6 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
|
||||||
{
|
{
|
||||||
struct fpstate *kstate = gfpu->fpstate;
|
struct fpstate *kstate = gfpu->fpstate;
|
||||||
const union fpregs_state *ustate = buf;
|
const union fpregs_state *ustate = buf;
|
||||||
struct pkru_state *xpkru;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) {
|
if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) {
|
||||||
if (ustate->xsave.header.xfeatures & ~XFEATURE_MASK_FPSSE)
|
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,
|
||||||
if (ustate->xsave.header.xfeatures & ~xcr0)
|
if (ustate->xsave.header.xfeatures & ~xcr0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = copy_uabi_from_kernel_to_xstate(kstate, ustate, vpkru);
|
return copy_uabi_from_kernel_to_xstate(kstate, ustate, vpkru);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* Retrieve PKRU if not in init state */
|
|
||||||
if (kstate->regs.xsave.header.xfeatures & XFEATURE_MASK_PKRU) {
|
|
||||||
xpkru = get_xsave_addr(&kstate->regs.xsave, XFEATURE_PKRU);
|
|
||||||
*vpkru = xpkru->pkru;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate);
|
EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate);
|
||||||
#endif /* CONFIG_KVM */
|
#endif /* CONFIG_KVM */
|
||||||
|
|
|
@ -1205,10 +1205,22 @@ static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size,
|
||||||
* @fpstate: The fpstate buffer to copy to
|
* @fpstate: The fpstate buffer to copy to
|
||||||
* @kbuf: The UABI format buffer, if it comes from the kernel
|
* @kbuf: The UABI format buffer, if it comes from the kernel
|
||||||
* @ubuf: The UABI format buffer, if it comes from userspace
|
* @ubuf: The UABI format buffer, if it comes from userspace
|
||||||
* @pkru: unused
|
* @pkru: The location to write the PKRU value to
|
||||||
*
|
*
|
||||||
* Converts from the UABI format into the kernel internal hardware
|
* Converts from the UABI format into the kernel internal hardware
|
||||||
* dependent format.
|
* dependent format.
|
||||||
|
*
|
||||||
|
* This function ultimately has three different callers with distinct PKRU
|
||||||
|
* behavior.
|
||||||
|
* 1. When called from sigreturn the PKRU register will be restored from
|
||||||
|
* @fpstate via an XRSTOR. Correctly copying the UABI format buffer to
|
||||||
|
* @fpstate is sufficient to cover this case, but the caller will also
|
||||||
|
* pass a pointer to the thread_struct's pkru field in @pkru and updating
|
||||||
|
* it is harmless.
|
||||||
|
* 2. When called from ptrace the PKRU register will be restored from the
|
||||||
|
* thread_struct's pkru field. A pointer to that is passed in @pkru.
|
||||||
|
* 3. When called from KVM the PKRU register will be restored from the vcpu's
|
||||||
|
* pkru field. A pointer to that is passed in @pkru.
|
||||||
*/
|
*/
|
||||||
static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
|
static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
|
||||||
const void __user *ubuf, u32 *pkru)
|
const void __user *ubuf, u32 *pkru)
|
||||||
|
@ -1260,6 +1272,13 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdr.xfeatures & XFEATURE_MASK_PKRU) {
|
||||||
|
struct pkru_state *xpkru;
|
||||||
|
|
||||||
|
xpkru = __raw_xsave_addr(xsave, XFEATURE_PKRU);
|
||||||
|
*pkru = xpkru->pkru;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The state that came in from userspace was user-state only.
|
* The state that came in from userspace was user-state only.
|
||||||
* Mask all the user states out of 'xfeatures':
|
* Mask all the user states out of 'xfeatures':
|
||||||
|
|
Loading…
Reference in New Issue