[PATCH v6 76/90] x86/microcode: Allocate cpuinfo_x86 snapshots on the heap

Ahmed S. Darwish posted 90 patches 6 days, 16 hours ago
[PATCH v6 76/90] x86/microcode: Allocate cpuinfo_x86 snapshots on the heap
Posted by Ahmed S. Darwish 6 days, 16 hours ago
load_late_stop_cpus() snapshots CPU capabilities before a late microcode
update, while microcode_check() snapshots the capabilities again after the
update.

Both functions allocate their struct cpuinfo_x86 snapshots on the stack.

Meanwhile, cpuinfo_x86 contains the parsed CPUID tables where more leaves
will be added; resulting in "stack frame length exceeded" warnings.

Allocate the before/after cpuinfo_x86 snapshots on the heap.

For load_late_stop_cpus(), do the memory allocation before the microcode
staging step.  This leaves no leaked or stale microcode state in -ENOMEM
failure modes.

Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
 arch/x86/kernel/cpu/common.c         | 11 ++++++++---
 arch/x86/kernel/cpu/microcode/core.c |  9 ++++++---
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 2beb53f6bed7..ece5a59124f5 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2543,15 +2543,20 @@ void store_cpu_caps(struct cpuinfo_x86 *curr_info)
  */
 void microcode_check(struct cpuinfo_x86 *prev_info)
 {
-	struct cpuinfo_x86 curr_info;
+	struct cpuinfo_x86 *curr_info __free(kfree) = kmalloc_obj(*curr_info);
 
 	perf_check_microcode();
 
 	amd_check_microcode();
 
-	store_cpu_caps(&curr_info);
+	if (!curr_info) {
+		pr_warn("x86/CPU: Microcode update CPU capability changes check was skipped (ENOMEM)\n");
+		return;
+	}
+
+	store_cpu_caps(curr_info);
 
-	if (!memcmp(&prev_info->x86_capability, &curr_info.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 56d791aeac4e..7a00671540bc 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -588,16 +588,19 @@ static int load_cpus_stopped(void *unused)
 
 static int load_late_stop_cpus(bool is_safe)
 {
+	struct cpuinfo_x86 *prev_info __free(kfree) = kmalloc_obj(*prev_info);
 	unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0;
 	unsigned int nr_offl, offline = 0;
 	int old_rev = boot_cpu_data.microcode;
-	struct cpuinfo_x86 prev_info;
 
 	if (!is_safe) {
 		pr_err("Late microcode loading without minimal revision check.\n");
 		pr_err("You should switch to early loading, if possible.\n");
 	}
 
+	if (!prev_info)
+		return -ENOMEM;
+
 	/*
 	 * Pre-load the microcode image into a staging device. This
 	 * process is preemptible and does not require stopping CPUs.
@@ -617,7 +620,7 @@ static int load_late_stop_cpus(bool is_safe)
 	 * 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);
+	store_cpu_caps(prev_info);
 
 	if (microcode_ops->use_nmi)
 		static_branch_enable_cpuslocked(&microcode_nmi_handler_enable);
@@ -666,7 +669,7 @@ static int load_late_stop_cpus(bool is_safe)
 		       num_online_cpus() - (updated + siblings));
 	}
 	pr_info("revision: 0x%x -> 0x%x\n", old_rev, boot_cpu_data.microcode);
-	microcode_check(&prev_info);
+	microcode_check(prev_info);
 
 	return updated + siblings == num_online_cpus() ? 0 : -EIO;
 }
-- 
2.53.0