[GIT pull] x86/urgent for v5.18-rc6

From: Thomas Gleixner
Date: Sun May 08 2022 - 08:07:20 EST


Linus,

please pull the latest x86/urgent branch from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-urgent-2022-05-08

up to: 59f5ede3bc0f: x86/fpu: Prevent FPU state corruption


A fix and an email address update:

- Prevent FPU state corruption. The condition in irq_fpu_usable() grants
FPU usage when the FPU is not used in the kernel. That's just wrong as
it does not take the fpregs_lock()'ed regions into account. If FPU usage
happens within such a region from interrupt context, then the FPU state
gets corrupted. That's a long standing bug, which got unearthed by the
recent changes to the random code.

- Josh wants to use his kernel.org email address


Thanks,

tglx

------------------>
Josh Poimboeuf (1):
MAINTAINERS: Update Josh Poimboeuf's email address

Thomas Gleixner (1):
x86/fpu: Prevent FPU state corruption


MAINTAINERS | 10 +++----
arch/x86/kernel/fpu/core.c | 67 ++++++++++++++++++----------------------------
2 files changed, 31 insertions(+), 46 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index edc96cdb85e8..1e1a2264792d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7499,7 +7499,7 @@ F: Documentation/hwmon/f71805f.rst
F: drivers/hwmon/f71805f.c

FADDR2LINE
-M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
+M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
S: Maintained
F: scripts/faddr2line

@@ -11348,7 +11348,7 @@ F: drivers/mmc/host/litex_mmc.c
N: litex

LIVE PATCHING
-M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
+M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
M: Jiri Kosina <jikos@xxxxxxxxxx>
M: Miroslav Benes <mbenes@xxxxxxx>
M: Petr Mladek <pmladek@xxxxxxxx>
@@ -14224,7 +14224,7 @@ F: lib/objagg.c
F: lib/test_objagg.c

OBJTOOL
-M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
+M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
M: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
S: Supported
F: tools/objtool/
@@ -18792,7 +18792,7 @@ F: include/dt-bindings/reset/starfive-jh7100.h

STATIC BRANCH/CALL
M: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
-M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
+M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
M: Jason Baron <jbaron@xxxxxxxxxx>
R: Steven Rostedt <rostedt@xxxxxxxxxxx>
R: Ard Biesheuvel <ardb@xxxxxxxxxx>
@@ -21444,7 +21444,7 @@ F: arch/x86/kernel/apic/x2apic_uv_x.c
F: arch/x86/platform/uv/

X86 STACK UNWINDING
-M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
+M: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
M: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
S: Supported
F: arch/x86/include/asm/unwind*.h
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index c049561f373a..e28ab0ecc537 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -41,17 +41,7 @@ struct fpu_state_config fpu_user_cfg __ro_after_init;
*/
struct fpstate init_fpstate __ro_after_init;

-/*
- * Track whether the kernel is using the FPU state
- * currently.
- *
- * This flag is used:
- *
- * - by IRQ context code to potentially use the FPU
- * if it's unused.
- *
- * - to debug kernel_fpu_begin()/end() correctness
- */
+/* Track in-kernel FPU usage */
static DEFINE_PER_CPU(bool, in_kernel_fpu);

/*
@@ -59,42 +49,37 @@ static DEFINE_PER_CPU(bool, in_kernel_fpu);
*/
DEFINE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx);

-static bool kernel_fpu_disabled(void)
-{
- return this_cpu_read(in_kernel_fpu);
-}
-
-static bool interrupted_kernel_fpu_idle(void)
-{
- return !kernel_fpu_disabled();
-}
-
-/*
- * Were we in user mode (or vm86 mode) when we were
- * interrupted?
- *
- * Doing kernel_fpu_begin/end() is ok if we are running
- * in an interrupt context from user mode - we'll just
- * save the FPU state as required.
- */
-static bool interrupted_user_mode(void)
-{
- struct pt_regs *regs = get_irq_regs();
- return regs && user_mode(regs);
-}
-
/*
* Can we use the FPU in kernel mode with the
* whole "kernel_fpu_begin/end()" sequence?
- *
- * It's always ok in process context (ie "not interrupt")
- * but it is sometimes ok even from an irq.
*/
bool irq_fpu_usable(void)
{
- return !in_interrupt() ||
- interrupted_user_mode() ||
- interrupted_kernel_fpu_idle();
+ if (WARN_ON_ONCE(in_nmi()))
+ return false;
+
+ /* In kernel FPU usage already active? */
+ if (this_cpu_read(in_kernel_fpu))
+ return false;
+
+ /*
+ * When not in NMI or hard interrupt context, FPU can be used in:
+ *
+ * - Task context except from within fpregs_lock()'ed critical
+ * regions.
+ *
+ * - Soft interrupt processing context which cannot happen
+ * while in a fpregs_lock()'ed critical region.
+ */
+ if (!in_hardirq())
+ return true;
+
+ /*
+ * In hard interrupt context it's safe when soft interrupts
+ * are enabled, which means the interrupt did not hit in
+ * a fpregs_lock()'ed critical region.
+ */
+ return !softirq_count();
}
EXPORT_SYMBOL(irq_fpu_usable);