x86/fpu: Allow PKRU to be (once again) written by ptrace.
authorKyle Huey <me@kylehuey.com>
Mon, 9 Jan 2023 21:02:12 +0000 (13:02 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 14 Jan 2023 09:23:27 +0000 (10:23 +0100)
commit 4a804c4f8356393d6b5eff7600f07615d7869c13 upstream

Handle PKRU in copy_uabi_to_xstate() for the benefit of 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.

Fixes: e84ba47e313d ("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
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kernel/fpu/xstate.c

index 8abce80..fe9050c 100644 (file)
@@ -1091,6 +1091,29 @@ static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size,
 }
 
 
+/**
+ * copy_uabi_to_xstate - Copy a UABI format buffer to the kernel xstate
+ * @fpstate:   The fpstate buffer to copy to
+ * @kbuf:      The UABI format buffer, if it comes from the kernel
+ * @ubuf:      The UABI format buffer, if it comes from userspace
+ * @pkru:      The location to write the PKRU value to
+ *
+ * Converts from the UABI format into the kernel internal hardware
+ * dependent format.
+ *
+ * This function ultimately has two 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.
+ *     The kernel will restore it manually, so the XRSTOR behavior that resets
+ *     the PKRU register to the hardware init value (0) if the corresponding
+ *     xfeatures bit is not set is emulated here.
+ */
 static int copy_uabi_to_xstate(struct xregs_state *xsave, const void *kbuf,
                               const void __user *ubuf, u32 *pkru)
 {
@@ -1140,6 +1163,13 @@ static int copy_uabi_to_xstate(struct xregs_state *xsave, 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.
         * Mask all the user states out of 'xfeatures':