Commit 27b5d61c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull x86 fix from Thomas Gleixner:
 "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"

* tag 'x86-urgent-2022-05-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/fpu: Prevent FPU state corruption
  MAINTAINERS: Update Josh Poimboeuf's email address
parents ea82593b 59f5ede3
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -7499,7 +7499,7 @@ F: Documentation/hwmon/f71805f.rst
F:	drivers/hwmon/f71805f.c
FADDR2LINE
M:	Josh Poimboeuf <jpoimboe@redhat.com>
M:	Josh Poimboeuf <jpoimboe@kernel.org>
S:	Maintained
F:	scripts/faddr2line
@@ -11348,7 +11348,7 @@ F: drivers/mmc/host/litex_mmc.c
N:	litex
LIVE PATCHING
M:	Josh Poimboeuf <jpoimboe@redhat.com>
M:	Josh Poimboeuf <jpoimboe@kernel.org>
M:	Jiri Kosina <jikos@kernel.org>
M:	Miroslav Benes <mbenes@suse.cz>
M:	Petr Mladek <pmladek@suse.com>
@@ -14224,7 +14224,7 @@ F: lib/objagg.c
F:	lib/test_objagg.c
OBJTOOL
M:	Josh Poimboeuf <jpoimboe@redhat.com>
M:	Josh Poimboeuf <jpoimboe@kernel.org>
M:	Peter Zijlstra <peterz@infradead.org>
S:	Supported
F:	tools/objtool/
@@ -18792,7 +18792,7 @@ F: include/dt-bindings/reset/starfive-jh7100.h
STATIC BRANCH/CALL
M:	Peter Zijlstra <peterz@infradead.org>
M:	Josh Poimboeuf <jpoimboe@redhat.com>
M:	Josh Poimboeuf <jpoimboe@kernel.org>
M:	Jason Baron <jbaron@akamai.com>
R:	Steven Rostedt <rostedt@goodmis.org>
R:	Ard Biesheuvel <ardb@kernel.org>
@@ -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@redhat.com>
M:	Josh Poimboeuf <jpoimboe@kernel.org>
M:	Peter Zijlstra <peterz@infradead.org>
S:	Supported
F:	arch/x86/include/asm/unwind*.h
+26 −41
Original line number Diff line number Diff line
@@ -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)
/*
 * Can we use the FPU in kernel mode with the
 * whole "kernel_fpu_begin/end()" sequence?
 */
bool irq_fpu_usable(void)
{
	return this_cpu_read(in_kernel_fpu);
}
	if (WARN_ON_ONCE(in_nmi()))
		return false;

static bool interrupted_kernel_fpu_idle(void)
{
	return !kernel_fpu_disabled();
}
	/* In kernel FPU usage already active? */
	if (this_cpu_read(in_kernel_fpu))
		return false;

	/*
 * Were we in user mode (or vm86 mode) when we were
 * interrupted?
	 * When not in NMI or hard interrupt context, FPU can be used in:
	 *
 * 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.
	 * - 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.
	 */
static bool interrupted_user_mode(void)
{
	struct pt_regs *regs = get_irq_regs();
	return regs && user_mode(regs);
}
	if (!in_hardirq())
		return true;

	/*
 * 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.
	 * 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.
	 */
bool irq_fpu_usable(void)
{
	return !in_interrupt() ||
		interrupted_user_mode() ||
		interrupted_kernel_fpu_idle();
	return !softirq_count();
}
EXPORT_SYMBOL(irq_fpu_usable);