Christina reported mismatched PKRU values from GDB coredump tests [1]. PKRU is stored in thread.pkru rather than in fpstate. Then the coredump path currently syncs fpstate only and hands thread.pkru to copy_xstate_to_uabi_buf(), so a task that still owns the register state can end up dumping a stale PKRU value. Save PKRU from the register when the target is the current task. Fixes: e84ba47e313d ("x86/fpu: Hook up PKRU into ptrace()") Closes: https://sourceware.org/bugzilla/show_bug.cgi?id=34646 # [1] Reported-by: Christina Joos Signed-off-by: Chang S. Bae Tested-by: Christina Joos Cc: stable@vger.kernel.org --- Testing: Christina verified the fix through the GDB tests that originally exposed the issue. Also a simple test that sets PKRU and triggers a coredump by dereferencing a NULL pointer can verify the saved PKRU from the corefile read. The existing ptrace selftests cover most of this path but not completely, e.g. not checking back from a corefile. So it may worth adding coredump tests for XSTATEs in general. I'd follow up on this separately. Code changes: The PKRU saving could be folded into sync_fpstate() similar to restore_fpregs_from_init_fpstate(). Instead, since this is on the saving path and PKRU storage is separate, sync_pkru() makes that dinstinction more explicit along with the fix. --- arch/x86/kernel/fpu/regset.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index 0986c2200adc..213a06fd72f3 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -49,6 +49,13 @@ static void sync_fpstate(struct fpu *fpu) fpu_sync_fpstate(fpu); } +/* Keep the same invocation context with sync_fpstate() */ +static void sync_pkru(struct task_struct *target) +{ + if (target == current) + target->thread.pkru = read_pkru(); +} + /* * Invalidate cached FPU registers before modifying the stopped target * task's fpstate. @@ -135,6 +142,9 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, sync_fpstate(x86_task_fpu(target)); + /* copy_xstate_to_uabi_buf() takes PKRU from thread.pkru */ + sync_pkru(target); + copy_xstate_to_uabi_buf(to, target, XSTATE_COPY_XSAVE); return 0; } -- 2.53.0