diff --git a/patches.suse/x86-fpu-prevent-fpu-state-corruption.patch b/patches.suse/x86-fpu-prevent-fpu-state-corruption.patch new file mode 100644 index 0000000..a73f119 --- /dev/null +++ b/patches.suse/x86-fpu-prevent-fpu-state-corruption.patch @@ -0,0 +1,139 @@ +From: Thomas Gleixner +Date: Sun, 1 May 2022 21:31:43 +0200 +Subject: x86/fpu: Prevent FPU state corruption +Git-commit: 59f5ede3bc0f00eb856425f636dab0c10feb06d8 +Patch-mainline: v5.18-rc6 +References: git-fixes + +The FPU usage related to task FPU management is either protected by +disabling interrupts (switch_to, return to user) or via fpregs_lock() which +is a wrapper around local_bh_disable(). When kernel code wants to use the +FPU then it has to check whether it is possible by calling irq_fpu_usable(). + +But the condition in irq_fpu_usable() is wrong. It allows FPU to be used +when: + + !in_interrupt() || interrupted_user_mode() || interrupted_kernel_fpu_idle() + +The latter is checking whether some other context already uses FPU in the +kernel, but if that's not the case then it allows FPU to be used +unconditionally even if the calling context interrupted a fpregs_lock() +critical region. If that happens then the FPU state of the interrupted +context becomes corrupted. + +Allow in kernel FPU usage only when no other context has in kernel FPU +usage and either the calling context is not hard interrupt context or the +hard interrupt did not interrupt a local bottomhalf disabled region. + +It's hard to find a proper Fixes tag as the condition was broken in one way +or the other for a very long time and the eager/lazy FPU changes caused a +lot of churn. Picked something remotely connected from the history. + +This survived undetected for quite some time as FPU usage in interrupt +context is rare, but the recent changes to the random code unearthed it at +least on a kernel which had FPU debugging enabled. There is probably a +higher rate of silent corruption as not all issues can be detected by the +FPU debugging code. This will be addressed in a subsequent change. + +Fixes: 5d2bd7009f30 ("x86, fpu: decouple non-lazy/eager fpu restore from xsave") +Reported-by: Filipe Manana +Signed-off-by: Thomas Gleixner +Tested-by: Filipe Manana +Reviewed-by: Borislav Petkov +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20220501193102.588689270@linutronix.de + +Acked-by: Nikolay Borisov +--- + arch/x86/kernel/fpu/core.c | 67 +++++++++++++++++---------------------------- + 1 file changed, 26 insertions(+), 41 deletions(-) + +--- a/arch/x86/kernel/fpu/core.c ++++ b/arch/x86/kernel/fpu/core.c +@@ -23,17 +23,7 @@ + */ + union fpregs_state init_fpstate __read_mostly; + +-/* +- * 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); + + /* +@@ -53,42 +43,37 @@ static void kernel_fpu_enable(void) + this_cpu_write(in_kernel_fpu, false); + } + +-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_irq()) ++ 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); + diff --git a/series.conf b/series.conf index 6147109..a3bd027 100644 --- a/series.conf +++ b/series.conf @@ -62537,6 +62537,7 @@ patches.suse/SUNRPC-Ensure-gss-proxy-connects-on-setup.patch patches.suse/Revert-SUNRPC-attempt-AF_LOCAL-connect-on-setup.patch patches.suse/floppy-use-a-statically-allocated-error-counter.patch + patches.suse/x86-fpu-prevent-fpu-state-corruption.patch patches.suse/writeback-Avoid-skipping-inode-writeback-846a3351ddfe.patch patches.suse/cgroup-cpuset-Remove-cpus_allowed-mems_allowed-setup-in-cpuset_init_smp.patch patches.suse/s390-ctcm-fix-variable-dereferenced-before-check