Skip to content

Commit f7ac25c

Browse files
hansendcxdevs23
authored andcommitted
x86/cpu: Help users notice when running old Intel microcode
Changes from v4: - Update list from commit: 8ac9378 microcode-20241112 Release Changes from v3: - Update changelog and documentation to clarify behavior when microcode is updated at runtime. Changes from v2: - Make cpu_latest_microcode[] static - Add a pr_info() when the CPU is not in the microcode version list Changes from v1: - Flesh out changelog - Add Documentation/ - add_taint() and pr_warn() in addition to vulnerabilities/ file - Add checks for running under VMMs. Do not taint and report vulnerability as unknown. From: Dave Hansen <[email protected]> Old microcode is bad for users and for kernel developers. For users, it exposes them to known fixed security and/or functional issues. These obviously rarely result in instant dumpster fires in every environment. But it is as important to keep your microcode up to date as it is to keep your kernel up to date. Old microcode also makes kernels harder to debug. A developer looking at an oops need to consider kernel bugs, known CPU issues and unknown CPU issues as possible causes. If they know the microcode is up to date, they can mostly eliminate known CPU issues as the cause. Make it easier to tell if CPU microcode is out of date. Add a list of released microcode. If the loaded microcode is older than the release, tell users in a place that folks can find it: /sys/devices/system/cpu/vulnerabilities/old_microcode Tell kernel kernel developers about it with the existing taint flag: TAINT_CPU_OUT_OF_SPEC == Discussion == When a user reports a potential kernel issue, it is very common to ask them to reproduce the issue on mainline. Running mainline, they will (independently from the distro) acquire a more up-to-date microcode version list. If their microcode is old, they will get a warning about the taint and kernel developers can take that into consideration when debugging. Just like any other entry in "vulnerabilities/", users are free to make their own assessment of their exposure. == Microcode Revision Discussion == The microcode versions in the table were generated from the Intel microcode git repo: 8ac9378a8487 ("microcode-20241112 Release") which as of this writing lags behind the latest microcode-20250211. It can be argued that the versions that the kernel picks to call "old" should be a revision or two old. Which specific version is picked is less important to me than picking *a* version and enforcing it. This repository contains only microcode versions that Intel has deemed to be OS-loadable. It is quite possible that the BIOS has loaded a newer microcode than the latest in this repo. If this happens, the system is considered to have new microcode, not old. Specifically, the sysfs file and taint flag answer the question: Is the CPU running on the latest OS-loadable microcode, or something even later that the BIOS loaded? In other words, Intel never publishes an authoritative list of CPUs and latest microcode revisions. Until it does, this is the best that Linux can do. Also note that the "intel-ucode-defs.h" file is simple, ugly and has lots of magic numbers. That's on purpose and should allow a single file to be shared across lots of stable kernel regardless of if they have the new "VFM" infrastructure or not. It was generated with a dumb script. == FAQ == Q: Does this tell me if my system is secure or insecure? A: No. It only tells you if your microcode was old when the system booted. Q: Should the kernel warn if the microcode list itself is too old? A: No. New kernels will get new microcode lists, both mainline and stable. The only way to have an old list is to be running an old kernel in which case you have bigger problems. Q: Is this for security or functional issues? A: Both. Q: If a given microcode update only has functional problems but no security issues, will it be considered old? A: Yes. All microcode image versions within a microcode release are treated identically. Intel appears to make security updates without disclosing them in the release notes. Thus, all updates are considered to be security-relevant. Q: Who runs old microcode? A: Anybody with an old distro. This happens all the time inside of Intel where there are lots of weird systems in labs that might not be getting regular distro updates and might also be running rather exotic microcode images. Q: If I update my microcode after booting will it stop saying "Vulnerable"? A: No. Just like all the other vulnerabilies, you need to reboot before the kernel will reassess your vulnerability. Signed-off-by: Dave Hansen <[email protected]> Link: https://lore.kernel.org/all/20250421195659.CF426C07%40davehans-spike.ostc.intel.com Signed-off-by: Simão Gomes Viana <[email protected]>
1 parent e44a6ae commit f7ac25c

8 files changed

Lines changed: 237 additions & 0 deletions

File tree

Documentation/ABI/testing/sysfs-devices-system-cpu

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ What: /sys/devices/system/cpu/vulnerabilities
516516
/sys/devices/system/cpu/vulnerabilities/mds
517517
/sys/devices/system/cpu/vulnerabilities/meltdown
518518
/sys/devices/system/cpu/vulnerabilities/mmio_stale_data
519+
/sys/devices/system/cpu/vulnerabilities/old_microcode
519520
/sys/devices/system/cpu/vulnerabilities/reg_file_data_sampling
520521
/sys/devices/system/cpu/vulnerabilities/retbleed
521522
/sys/devices/system/cpu/vulnerabilities/spec_store_bypass
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
=============
4+
Old Microcode
5+
=============
6+
7+
The kernel keeps a table of released microcode. Systems that had
8+
microcode older than this at boot will say "Vulnerable". This means
9+
that the system was vulnerable to some known CPU issue. It could be
10+
security or functional, the kernel does not know or care.
11+
12+
You should update the CPU microcode to mitigate any exposure. This is
13+
usually accomplished by updating the files in
14+
/lib/firmware/intel-ucode/ via normal distribution updates. Intel also
15+
distributes these files in a github repo:
16+
17+
https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files.git
18+
19+
Just like all the other hardware vulnerabilities, exposure is
20+
determined at boot. Runtime microcode updates do not change the status
21+
of this vulnerability.

arch/x86/include/asm/cpufeatures.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,4 +535,6 @@
535535
#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
536536
#define X86_BUG_BHI X86_BUG(1*32 + 3) /* "bhi" CPU is affected by Branch History Injection */
537537
#define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */
538+
#define X86_BUG_SPECTRE_V2_USER X86_BUG(1*32 + 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
539+
#define X86_BUG_OLD_MICROCODE X86_BUG(1*32 + 6) /* "old_microcode" CPU has old microcode, it is surely vulnerable to something */
538540
#endif /* _ASM_X86_CPUFEATURES_H */

arch/x86/kernel/cpu/bugs.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2806,6 +2806,14 @@ static ssize_t rfds_show_state(char *buf)
28062806
return sysfs_emit(buf, "%s\n", rfds_strings[rfds_mitigation]);
28072807
}
28082808

2809+
static ssize_t old_microcode_show_state(char *buf)
2810+
{
2811+
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
2812+
return sysfs_emit(buf, "Unknown: running under hypervisor");
2813+
2814+
return sysfs_emit(buf, "Vulnerable\n");
2815+
}
2816+
28092817
static char *stibp_state(void)
28102818
{
28112819
if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) &&
@@ -2988,6 +2996,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
29882996
case X86_BUG_RFDS:
29892997
return rfds_show_state(buf);
29902998

2999+
case X86_BUG_OLD_MICROCODE:
3000+
return old_microcode_show_state(buf);
3001+
29913002
default:
29923003
break;
29933004
}
@@ -3067,6 +3078,11 @@ ssize_t cpu_show_reg_file_data_sampling(struct device *dev, struct device_attrib
30673078
{
30683079
return cpu_show_common(dev, attr, buf, X86_BUG_RFDS);
30693080
}
3081+
3082+
ssize_t cpu_show_old_microcode(struct device *dev, struct device_attribute *attr, char *buf)
3083+
{
3084+
return cpu_show_common(dev, attr, buf, X86_BUG_OLD_MICROCODE);
3085+
}
30703086
#endif
30713087

30723088
void __warn_thunk(void)

arch/x86/kernel/cpu/common.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,10 +1317,52 @@ static bool __init vulnerable_to_rfds(u64 x86_arch_cap_msr)
13171317
return cpu_matches(cpu_vuln_blacklist, RFDS);
13181318
}
13191319

1320+
static struct x86_cpu_id cpu_latest_microcode[] = {
1321+
#include "microcode/intel-ucode-defs.h"
1322+
{}
1323+
};
1324+
1325+
static bool __init cpu_has_old_microcode(void)
1326+
{
1327+
const struct x86_cpu_id *m = x86_match_cpu(cpu_latest_microcode);
1328+
1329+
/* Give unknown CPUs a pass: */
1330+
if (!m) {
1331+
/* Intel CPUs should be in the list. Warn if not: */
1332+
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
1333+
pr_info("x86/CPU: Model not found in latest microcode list\n");
1334+
return false;
1335+
}
1336+
1337+
/*
1338+
* Hosts usually lie to guests with a super high microcode
1339+
* version. Just ignore what hosts tell guests:
1340+
*/
1341+
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
1342+
return false;
1343+
1344+
/* Consider all debug microcode to be old: */
1345+
if (boot_cpu_data.microcode & BIT(31))
1346+
return true;
1347+
1348+
/* Give new microocode a pass: */
1349+
if (boot_cpu_data.microcode >= m->driver_data)
1350+
return false;
1351+
1352+
/* Uh oh, too old: */
1353+
return true;
1354+
}
1355+
13201356
static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
13211357
{
13221358
u64 x86_arch_cap_msr = x86_read_arch_cap_msr();
13231359

1360+
if (cpu_has_old_microcode()) {
1361+
pr_warn("x86/CPU: Running old microcode\n");
1362+
setup_force_cpu_bug(X86_BUG_OLD_MICROCODE);
1363+
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
1364+
}
1365+
13241366
/* Set ITLB_MULTIHIT bug if cpu is not in the whitelist and not mitigated */
13251367
if (!cpu_matches(cpu_vuln_whitelist, NO_ITLB_MULTIHIT) &&
13261368
!(x86_arch_cap_msr & ARCH_CAP_PSCHANGE_MC_NO))

0 commit comments

Comments
 (0)