blob: 90a392e4128ef0c1d97ce02ea902f7df4c26a0bf [file] [log] [blame]
From 627650d2af920634a0f373d692d38d1dc3c31023 Mon Sep 17 00:00:00 2001
From: Sebastian Andrzej Siewior <>
Date: Fri, 20 Dec 2019 20:59:06 +0100
Subject: [PATCH] x86/fpu: Deactivate FPU state after failure during state load
commit bbc55341b9c67645d1a5471506370caf7dd4a203 upstream.
In __fpu__restore_sig(), fpu_fpregs_owner_ctx needs to be reset if the
FPU state was not fully restored. Otherwise the following may happen (on
the same CPU):
Task A Task B fpu_fpregs_owner_ctx
*active* A.fpu
ctx switch load B.fpu
*active* B.fpu
copy_kernel_to_xregs() *modify*
copy_user_to_xregs() *fails*
ctx switch skip loading B.fpu,
*active* B.fpu
In the success case, fpu_fpregs_owner_ctx is set to the current task.
In the failure case, the FPU state might have been modified by loading
the init state.
In this case, fpu_fpregs_owner_ctx needs to be reset in order to ensure
that the FPU state of the following task is loaded from saved state (and
not skipped because it was the previous state).
Reset fpu_fpregs_owner_ctx after a failure during restore occurred, to
ensure that the FPU state for the next task is always loaded.
The problem was debugged-by Yu-cheng Yu <>.
[ bp: Massage commit message. ]
Fixes: 5f409e20b7945 ("x86/fpu: Defer FPU state load until return to userspace")
Reported-by: Yu-cheng Yu <>
Signed-off-by: Sebastian Andrzej Siewior <>
Signed-off-by: Borislav Petkov <>
Cc: Andy Lutomirski <>
Cc: Dave Hansen <>
Cc: Fenghua Yu <>
Cc: "H. Peter Anvin" <>
Cc: Ingo Molnar <>
Cc: Jann Horn <>
Cc: Peter Zijlstra <>
Cc: "Ravi V. Shankar" <>
Cc: Rik van Riel <>
Cc: Thomas Gleixner <>
Cc: Tony Luck <>
Cc: x86-ml <>
Signed-off-by: Paul Gortmaker <>
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
index 0071b794ed19..400a05e1c1c5 100644
--- a/arch/x86/kernel/fpu/signal.c
+++ b/arch/x86/kernel/fpu/signal.c
@@ -352,6 +352,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
return 0;
+ fpregs_deactivate(fpu);
@@ -403,6 +404,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
if (!ret)
+ else
+ fpregs_deactivate(fpu);