Skip to content

Commit d8778e3

Browse files
amlutosuryasaimadhu
authored andcommitted
x86/fpu: Invalidate FPU state after a failed XRSTOR from a user buffer
Both Intel and AMD consider it to be architecturally valid for XRSTOR to fail with #PF but nonetheless change the register state. The actual conditions under which this might occur are unclear [1], but it seems plausible that this might be triggered if one sibling thread unmaps a page and invalidates the shared TLB while another sibling thread is executing XRSTOR on the page in question. __fpu__restore_sig() can execute XRSTOR while the hardware registers are preserved on behalf of a different victim task (using the fpu_fpregs_owner_ctx mechanism), and, in theory, XRSTOR could fail but modify the registers. If this happens, then there is a window in which __fpu__restore_sig() could schedule out and the victim task could schedule back in without reloading its own FPU registers. This would result in part of the FPU state that __fpu__restore_sig() was attempting to load leaking into the victim task's user-visible state. Invalidate preserved FPU registers on XRSTOR failure to prevent this situation from corrupting any state. [1] Frequent readers of the errata lists might imagine "complex microarchitectural conditions". Fixes: 1d731e7 ("x86/fpu: Add a fastpath to __fpu__restore_sig()") Signed-off-by: Andy Lutomirski <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Acked-by: Dave Hansen <[email protected]> Acked-by: Rik van Riel <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent 484cea4 commit d8778e3

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

arch/x86/kernel/fpu/signal.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,25 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
369369
fpregs_unlock();
370370
return 0;
371371
}
372+
373+
/*
374+
* The above did an FPU restore operation, restricted to
375+
* the user portion of the registers, and failed, but the
376+
* microcode might have modified the FPU registers
377+
* nevertheless.
378+
*
379+
* If the FPU registers do not belong to current, then
380+
* invalidate the FPU register state otherwise the task might
381+
* preempt current and return to user space with corrupted
382+
* FPU registers.
383+
*
384+
* In case current owns the FPU registers then no further
385+
* action is required. The fixup below will handle it
386+
* correctly.
387+
*/
388+
if (test_thread_flag(TIF_NEED_FPU_LOAD))
389+
__cpu_invalidate_fpregs_state();
390+
372391
fpregs_unlock();
373392
} else {
374393
/*

0 commit comments

Comments
 (0)