linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: x86@kernel.org, Borislav Petkov <bp@alien8.de>,
	Ashok Raj <ashok.raj@intel.com>,
	Arjan van de Ven <arjan@linux.intel.com>
Subject: [patch 29/30] x86/microcode: Prepare for minimal revision check
Date: Thu, 10 Aug 2023 20:38:09 +0200 (CEST)	[thread overview]
Message-ID: <20230810160806.617422055@linutronix.de> (raw)
In-Reply-To: 20230810153317.850017756@linutronix.de

From: Thomas Gleixner <tglx@linutronix.de>

Applying microcode late can be fatal for the running kernel when the update
changes functionality which is in use already in a non-compatible way,
e.g. by removing a CPUID bit.

There is no way for admins which do not have access to the vendors deep
technical support to decide whether late loading of such a microcode is
safe or not.

Intel has added a new field to the microcode header which tells the minimal
microcode revision which is required to be active in the CPU in order to be
safe.

Provide infrastructure for handling this in the core code and a command
line switch which allows to enforce it.

If the update is considered safe the kernel is not tainted and the annoying
warning message not emitted. If it's enforced and the currently loaded
microcode revision is not safe for late loading then the load is aborted.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

---
 Documentation/admin-guide/kernel-parameters.txt |    5 ++++
 arch/x86/Kconfig                                |   23 ++++++++++++++++++-
 arch/x86/kernel/cpu/microcode/amd.c             |    3 ++
 arch/x86/kernel/cpu/microcode/core.c            |   29 ++++++++++++++++++------
 arch/x86/kernel/cpu/microcode/intel.c           |    3 ++
 arch/x86/kernel/cpu/microcode/internal.h        |    3 ++
 6 files changed, 58 insertions(+), 8 deletions(-)
---
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3239,6 +3239,11 @@
 
 	mga=		[HW,DRM]
 
+	microcode.force_minrev=	[X86]
+			Format: <bool>
+			Enable or disable the microcode minimal revision
+			enforcement for the runtime microcode loader.
+
 	min_addr=nn[KMG]	[KNL,BOOT,IA-64] All physical memory below this
 			physical address is ignored.
 
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1320,7 +1320,28 @@ config MICROCODE_LATE_LOADING
 	  is a tricky business and should be avoided if possible. Just the sequence
 	  of synchronizing all cores and SMT threads is one fragile dance which does
 	  not guarantee that cores might not softlock after the loading. Therefore,
-	  use this at your own risk. Late loading taints the kernel too.
+	  use this at your own risk. Late loading taints the kernel unless the
+	  microcode header indicates that it is safe for late loading via the
+	  minimal revision check. This minimal revision check can be enforced on
+	  the kernel command line with "microcode.minrev=Y".
+
+config MICROCODE_LATE_FORCE_MINREV
+	bool "Enforce late microcode loading minimal revision check"
+	default n
+	depends on MICROCODE_LATE_LOADING
+	help
+	  To prevent that users load microcode late which modifies already
+	  in use features, newer microcodes have a minimum revision field
+	  in the microcode header, which tells the kernel which minimum
+	  revision must be active in the CPU to safely load that new microcode
+	  late into the running system. If disabled the check will not
+	  be enforced but the kernel will be tainted when the minimal
+	  revision check fails.
+
+	  This minimal revision check can also be controlled via the
+	  "microcode.minrev" parameter on the kernel command line.
+
+	  If unsure say Y.
 
 config X86_MSR
 	tristate "/dev/cpu/*/msr - Model-specific register support"
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -880,6 +880,9 @@ static enum ucode_state request_microcod
 	enum ucode_state ret = UCODE_NFOUND;
 	const struct firmware *fw;
 
+	if (force_minrev)
+		return UCODE_NFOUND;
+
 	if (c->x86 >= 0x15)
 		snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
 
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -46,6 +46,9 @@
 static struct microcode_ops	*microcode_ops;
 static bool dis_ucode_ldr = true;
 
+bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
+module_param(force_minrev, bool, S_IRUSR | S_IWUSR);
+
 bool initrd_gone;
 
 /*
@@ -601,15 +604,17 @@ static int ucode_load_cpus_stopped(void
 	return 0;
 }
 
-static int ucode_load_late_stop_cpus(void)
+static int ucode_load_late_stop_cpus(bool is_safe)
 {
 	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;
 
-	pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n");
-	pr_err("You should switch to early loading, if possible.\n");
+	if (!is_safe) {
+		pr_err("Late microcode loading without minimal revision check.\n");
+		pr_err("You should switch to early loading, if possible.\n");
+	}
 
 	atomic_set(&late_cpus_in, num_online_cpus());
 	atomic_set(&offline_in_nmi, 0);
@@ -659,7 +664,9 @@ static int ucode_load_late_stop_cpus(voi
 		return -EIO;
 	}
 
-	add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+	if (!is_safe || failed || timedout)
+		add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+
 	pr_info("Microcode load: updated on %u primary CPUs with %u siblings\n", updated, siblings);
 	if (failed || timedout) {
 		pr_err("Microcode load incomplete. %u CPUs timed out or failed\n",
@@ -753,9 +760,17 @@ static int ucode_load_late_locked(void)
 		return -EBUSY;
 
 	ret = microcode_ops->request_microcode_fw(0, &microcode_pdev->dev);
-	if (ret != UCODE_NEW)
-		return ret == UCODE_NFOUND ? -ENOENT : -EBADFD;
-	return ucode_load_late_stop_cpus();
+
+	switch (ret) {
+	case UCODE_NEW:
+	case UCODE_NEW_SAFE:
+		break;
+	case UCODE_NFOUND:
+		return -ENOENT;
+	default:
+		return -EBADFD;
+	}
+	return ucode_load_late_stop_cpus(ret == UCODE_NEW_SAFE);
 }
 
 static ssize_t reload_store(struct device *dev,
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -549,6 +549,9 @@ static enum ucode_state read_ucode_intel
 	int cur_rev = uci->cpu_sig.rev;
 	u8 *new_mc = NULL, *mc = NULL;
 
+	if (force_minrev)
+		return UCODE_NFOUND;
+
 	while (iov_iter_count(iter)) {
 		struct microcode_header_intel mc_header;
 		unsigned int mc_size, data_size;
--- a/arch/x86/kernel/cpu/microcode/internal.h
+++ b/arch/x86/kernel/cpu/microcode/internal.h
@@ -13,6 +13,7 @@ struct device;
 enum ucode_state {
 	UCODE_OK	= 0,
 	UCODE_NEW,
+	UCODE_NEW_SAFE,
 	UCODE_UPDATED,
 	UCODE_NFOUND,
 	UCODE_ERROR,
@@ -36,6 +37,8 @@ struct microcode_ops {
 				use_nmi		: 1;
 };
 
+extern bool force_minrev;
+
 extern struct ucode_cpu_info ucode_cpu_info[];
 struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa);
 


  parent reply	other threads:[~2023-08-10 18:39 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-10 18:37 [patch 00/30] x86/microcode: Cleanup and late loading enhancements Thomas Gleixner
2023-08-10 18:37 ` [patch 01/30] x86/mm: Remove unused microcode.h include Thomas Gleixner
2023-08-10 18:37 ` [patch 02/30] x86/microcode: Hide the config knob Thomas Gleixner
2023-08-10 20:41   ` Ashok Raj
2023-08-11 11:22     ` Borislav Petkov
2023-08-10 18:37 ` [patch 03/30] x86/microcode/intel: Move microcode functions out of cpu/intel.c Thomas Gleixner
2023-08-10 18:37 ` [patch 04/30] x86/microcode: Include vendor headers into microcode.h Thomas Gleixner
2023-08-10 18:37 ` [patch 05/30] x86/microcode: Make reload_early_microcode() static Thomas Gleixner
2023-08-10 18:37 ` [patch 06/30] x86/microcode/intel: Rename get_datasize() since its used externally Thomas Gleixner
2023-08-10 18:37 ` [patch 07/30] x86/microcode: Move core specific defines to local header Thomas Gleixner
2023-08-10 18:37 ` [patch 08/30] x86/microcode/intel: Rip out mixed stepping support for Intel CPUs Thomas Gleixner
2023-08-11 22:25   ` Borislav Petkov
2023-08-12  7:16     ` Thomas Gleixner
2023-08-10 18:37 ` [patch 09/30] x86/microcode/intel: Remove debug code Thomas Gleixner
2023-08-11 10:45   ` Nikolay Borisov
2023-08-10 18:37 ` [patch 10/30] x86/microcode: Remove pointless mutex Thomas Gleixner
2023-08-10 18:37 ` [patch 11/30] x86/microcode/intel: Simplify scan_microcode() Thomas Gleixner
2023-08-10 18:37 ` [patch 12/30] x86/microcode/intel: Simplify and rename generic_load_microcode() Thomas Gleixner
2023-08-10 18:37 ` [patch 13/30] x86/microcode/intel: Cleanup code further Thomas Gleixner
2023-08-11 11:01   ` Nikolay Borisov
2023-08-10 18:37 ` [patch 14/30] x86/microcode/intel: Simplify early loading Thomas Gleixner
2023-08-10 18:37 ` [patch 15/30] x86/microcode/intel: Save the microcode only after a successful late-load Thomas Gleixner
2023-08-10 18:37 ` [patch 16/30] x86/microcode/intel: Switch to kvmalloc() Thomas Gleixner
2023-08-10 18:37 ` [patch 17/30] x86/microcode/intel: Unify microcode apply() functions Thomas Gleixner
2023-08-10 18:37 ` [patch 18/30] x86/microcode: Handle "nosmt" correctly Thomas Gleixner
2023-08-10 18:37 ` [patch 19/30] x86/microcode: Clarify the late load logic Thomas Gleixner
2023-08-10 18:37 ` [patch 20/30] x86/microcode: Sanitize __wait_for_cpus() Thomas Gleixner
2023-08-10 18:37 ` [patch 21/30] x86/microcode: Add per CPU result state Thomas Gleixner
2023-08-10 18:37 ` [patch 22/30] x86/microcode: Add per CPU control field Thomas Gleixner
2023-08-10 18:38 ` [patch 23/30] x86/microcode: Provide new control functions Thomas Gleixner
2023-08-10 20:25   ` Peter Zijlstra
2023-08-10 18:38 ` [patch 24/30] x86/microcode: Replace the all in one rendevouz handler Thomas Gleixner
2023-08-10 18:38 ` [patch 25/30] x86/microcode: Rendezvous and load in NMI Thomas Gleixner
2023-08-10 18:38 ` [patch 26/30] x86/microcode: Protect against instrumentation Thomas Gleixner
2023-08-10 20:36   ` Peter Zijlstra
2023-08-11  9:19     ` Thomas Gleixner
2023-08-10 18:38 ` [patch 27/30] x86/apic: Provide apic_force_nmi_on_cpu() Thomas Gleixner
2023-08-10 18:38 ` [patch 28/30] x86/microcode: Handle "offline" CPUs correctly Thomas Gleixner
2023-08-10 20:46   ` Peter Zijlstra
2023-08-10 20:50     ` Ashok Raj
2023-08-10 21:05       ` Peter Zijlstra
2023-08-10 21:49         ` Ashok Raj
2023-08-10 22:29           ` Peter Zijlstra
2023-08-10 23:02             ` Ashok Raj
2023-08-11  1:19               ` Thomas Gleixner
2023-08-11  1:31                 ` Thomas Gleixner
2023-08-11  9:36     ` Thomas Gleixner
2023-08-12 16:47       ` Thomas Gleixner
2023-08-10 18:38 ` Thomas Gleixner [this message]
2023-08-10 20:54   ` [patch 29/30] x86/microcode: Prepare for minimal revision check Peter Zijlstra
2023-08-11  9:38     ` Thomas Gleixner
2023-08-11 14:20     ` Arjan van de Ven
2023-08-10 18:38 ` [patch 30/30] x86/microcode/intel: Add a minimum required revision for late-loads Thomas Gleixner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230810160806.617422055@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=arjan@linux.intel.com \
    --cc=ashok.raj@intel.com \
    --cc=bp@alien8.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).