forked from rpms/kernel
136 lines
4.8 KiB
Diff
136 lines
4.8 KiB
Diff
From a8cd7508b4dfd8cedd394da8cdb0253f18bdb1a8 Mon Sep 17 00:00:00 2001
|
|
From: Ashok Raj <ashok.raj@intel.com>
|
|
Date: Mon, 9 Jan 2023 07:35:51 -0800
|
|
Subject: [PATCH 14/36] x86/microcode: Check CPU capabilities after late
|
|
microcode update correctly
|
|
|
|
The kernel caches each CPU's feature bits at boot in an x86_capability[]
|
|
structure. However, the capabilities in the BSP's copy can be turned off
|
|
as a result of certain command line parameters or configuration
|
|
restrictions, for example the SGX bit. This can cause a mismatch when
|
|
comparing the values before and after the microcode update.
|
|
|
|
microcode_check() is called after an update to report any previously
|
|
cached CPUID bits which might have changed due to the update.
|
|
|
|
Therefore, store the cached CPU caps before the update and compare them
|
|
with the CPU caps after the microcode update has succeeded.
|
|
|
|
Thus, the comparison is done between the CPUID *hardware* bits before
|
|
and after the upgrade instead of using the cached, possibly runtime
|
|
modified values in BSP's boot_cpu_data copy.
|
|
|
|
As a result, false warnings about CPUID bits changes are avoided.
|
|
|
|
[ bp:
|
|
- Massage.
|
|
- Add SRBDS_CTRL example.
|
|
- Add kernel-doc.
|
|
- Incorporate forgotten review feedback from dhansen.
|
|
]
|
|
|
|
Fixes: 1008c52c09dc ("x86/CPU: Add a microcode loader callback")
|
|
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
|
|
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
|
|
Link: https://lore.kernel.org/r/20230109153555.4986-3-ashok.raj@intel.com
|
|
(cherry picked from commit c0dd9245aa9e25a697181f6085692272c9ec61bc)
|
|
|
|
CVE: CVE-2023-20593
|
|
Signed-off-by: Mridula Shastry <mridula.c.shastry@oracle.com>
|
|
Reviewed-by: Todd Vierling <todd.vierling@oracle.com>
|
|
---
|
|
arch/x86/include/asm/processor.h | 1 +
|
|
arch/x86/kernel/cpu/common.c | 36 ++++++++++++++++++----------
|
|
arch/x86/kernel/cpu/microcode/core.c | 6 +++++
|
|
3 files changed, 30 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
|
|
index 9968d456d7e8..820104bdee1f 100644
|
|
--- a/arch/x86/include/asm/processor.h
|
|
+++ b/arch/x86/include/asm/processor.h
|
|
@@ -920,6 +920,7 @@ bool xen_set_default_idle(void);
|
|
void stop_this_cpu(void *dummy);
|
|
void df_debug(struct pt_regs *regs, long error_code);
|
|
void microcode_check(struct cpuinfo_x86 *prev_info);
|
|
+void store_cpu_caps(struct cpuinfo_x86 *info);
|
|
|
|
enum l1tf_mitigations {
|
|
L1TF_MITIGATION_OFF,
|
|
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
|
|
index 437fe55acce8..22763a691b7b 100644
|
|
--- a/arch/x86/kernel/cpu/common.c
|
|
+++ b/arch/x86/kernel/cpu/common.c
|
|
@@ -2146,6 +2146,25 @@ void cpu_init_secondary(void)
|
|
#endif
|
|
|
|
#ifdef CONFIG_MICROCODE_LATE_LOADING
|
|
+/**
|
|
+ * store_cpu_caps() - Store a snapshot of CPU capabilities
|
|
+ * @curr_info: Pointer where to store it
|
|
+ *
|
|
+ * Returns: None
|
|
+ */
|
|
+void store_cpu_caps(struct cpuinfo_x86 *curr_info)
|
|
+{
|
|
+ /* Reload CPUID max function as it might've changed. */
|
|
+ curr_info->cpuid_level = cpuid_eax(0);
|
|
+
|
|
+ /* Copy all capability leafs and pick up the synthetic ones. */
|
|
+ memcpy(&curr_info->x86_capability, &boot_cpu_data.x86_capability,
|
|
+ sizeof(curr_info->x86_capability));
|
|
+
|
|
+ /* Get the hardware CPUID leafs */
|
|
+ get_cpu_cap(curr_info);
|
|
+}
|
|
+
|
|
/**
|
|
* microcode_check() - Check if any CPU capabilities changed after an update.
|
|
* @prev_info: CPU capabilities stored before an update.
|
|
@@ -2158,22 +2177,13 @@ void cpu_init_secondary(void)
|
|
*/
|
|
void microcode_check(struct cpuinfo_x86 *prev_info)
|
|
{
|
|
- perf_check_microcode();
|
|
-
|
|
- /* Reload CPUID max function as it might've changed. */
|
|
- prev_info->cpuid_level = cpuid_eax(0);
|
|
+ struct cpuinfo_x86 curr_info;
|
|
|
|
- /*
|
|
- * Copy all capability leafs to pick up the synthetic ones so that
|
|
- * memcmp() below doesn't fail on that. The ones coming from CPUID will
|
|
- * get overwritten in get_cpu_cap().
|
|
- */
|
|
- memcpy(&prev_info->x86_capability, &boot_cpu_data.x86_capability,
|
|
- sizeof(prev_info->x86_capability));
|
|
+ perf_check_microcode();
|
|
|
|
- get_cpu_cap(prev_info);
|
|
+ store_cpu_caps(&curr_info);
|
|
|
|
- if (!memcmp(&prev_info->x86_capability, &boot_cpu_data.x86_capability,
|
|
+ if (!memcmp(&prev_info->x86_capability, &curr_info.x86_capability,
|
|
sizeof(prev_info->x86_capability)))
|
|
return;
|
|
|
|
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
|
|
index 41a90074df21..9df2c40a4ddf 100644
|
|
--- a/arch/x86/kernel/cpu/microcode/core.c
|
|
+++ b/arch/x86/kernel/cpu/microcode/core.c
|
|
@@ -465,6 +465,12 @@ static int microcode_reload_late(void)
|
|
atomic_set(&late_cpus_in, 0);
|
|
atomic_set(&late_cpus_out, 0);
|
|
|
|
+ /*
|
|
+ * Take a snapshot before the microcode update in order to compare and
|
|
+ * check whether any bits changed after an update.
|
|
+ */
|
|
+ store_cpu_caps(&prev_info);
|
|
+
|
|
ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
|
|
if (ret == 0)
|
|
microcode_check(&prev_info);
|
|
--
|
|
2.39.3
|
|
|