diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-08 11:21:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-08 11:21:54 -0700 |
commit | 27b5d61c0c0c4ba347b514ade27f7919b032778e (patch) | |
tree | 8e0f3226f923684b25d41921bab4ff2cec3090db | |
parent | ea82593bad9a77f6f14c9701c13ff7368b22f027 (diff) | |
parent | 59f5ede3bc0f00eb856425f636dab0c10feb06d8 (diff) |
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
-rw-r--r-- | MAINTAINERS | 10 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/core.c | 67 |
2 files changed, 31 insertions, 46 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 97fb18c7c26c..e8c52d0192a6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 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); |