mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-04-09 10:13:18 +02:00
new batch mode docs, add doc/ to -build branch
This commit is contained in:
10
dist/README.md
vendored
10
dist/README.md
vendored
@@ -214,17 +214,17 @@ A race condition in the branch predictor update mechanism of Intel processors (C
|
||||
Several transient execution CVEs are not covered by this tool, for various reasons (duplicates, only
|
||||
affecting non-supported hardware or OS, theoretical with no known exploitation, etc.).
|
||||
The complete list along with the reason for each exclusion is available in the
|
||||
[UNSUPPORTED_CVE_LIST.md](https://github.com/speed47/spectre-meltdown-checker/blob/source/UNSUPPORTED_CVE_LIST.md) file.
|
||||
[UNSUPPORTED_CVE_LIST.md](doc/UNSUPPORTED_CVE_LIST.md) file.
|
||||
|
||||
## Scope
|
||||
|
||||
Supported operating systems:
|
||||
- Linux (all versions, flavors and distros)
|
||||
- FreeBSD, NetBSD, DragonFlyBSD and derivatives (others BSDs are [not supported](FAQ.md#which-bsd-oses-are-supported))
|
||||
- FreeBSD, NetBSD, DragonFlyBSD and derivatives (others BSDs are [not supported](doc/FAQ.md#which-bsd-oses-are-supported))
|
||||
|
||||
For Linux systems, the tool will detect mitigations, including backported non-vanilla patches, regardless of the advertised kernel version number and the distribution (such as Debian, Ubuntu, CentOS, RHEL, Fedora, openSUSE, Arch, ...), it also works if you've compiled your own kernel. More information [here](FAQ.md#how-does-this-script-work).
|
||||
For Linux systems, the tool will detect mitigations, including backported non-vanilla patches, regardless of the advertised kernel version number and the distribution (such as Debian, Ubuntu, CentOS, RHEL, Fedora, openSUSE, Arch, ...), it also works if you've compiled your own kernel. More information [here](doc/FAQ.md#how-does-this-script-work).
|
||||
|
||||
Other operating systems such as MacOS, Windows, ESXi, etc. [will never be supported](FAQ.md#why-is-my-os-not-supported).
|
||||
Other operating systems such as MacOS, Windows, ESXi, etc. [will never be supported](doc/FAQ.md#why-is-my-os-not-supported).
|
||||
|
||||
Supported architectures:
|
||||
- `x86` (32 bits)
|
||||
@@ -236,7 +236,7 @@ Supported architectures:
|
||||
|
||||
What is the purpose of this tool? Why was it written? How can it be useful to me? How does it work? What can I expect from it?
|
||||
|
||||
All these questions (and more) have detailed answers in the [FAQ](FAQ.md), please have a look!
|
||||
All these questions (and more) have detailed answers in the [FAQ](doc/FAQ.md), please have a look!
|
||||
|
||||
## Operating modes
|
||||
|
||||
|
||||
2
dist/FAQ.md → dist/doc/FAQ.md
vendored
2
dist/FAQ.md → dist/doc/FAQ.md
vendored
@@ -85,7 +85,7 @@ However I see a few reasons why this script might still be useful to you, and th
|
||||
|
||||
- The script can be pointed at a kernel image, and will deep dive into it, telling you if this kernel will mitigate vulnerabilities that might be present on your system. This is a good way to verify before booting a new kernel, that it'll mitigate the vulnerabilities you expect it to, especially if you modified a few config options around these topics.
|
||||
|
||||
- The script will also work regardless of the custom patches that might be integrated in the kernel you're running (or you're pointing it to, in offline mode), and completely ignores the advertised kernel version, to tell whether a given kernel mitigates vulnerabilities. This is especially useful for non-vanilla kernel, where patches might be backported, sometimes silently (this has already happened, too).
|
||||
- The script will also work regardless of the custom patches that might be integrated in the kernel you're running (or you're pointing it to, in no-runtime mode), and completely ignores the advertised kernel version, to tell whether a given kernel mitigates vulnerabilities. This is especially useful for non-vanilla kernel, where patches might be backported, sometimes silently (this has already happened, too).
|
||||
|
||||
- Educational purposes: the script gives interesting insights about a vulnerability, and how the different parts of the system work together to mitigate it.
|
||||
|
||||
298
dist/doc/UNSUPPORTED_CVE_LIST.md
vendored
Normal file
298
dist/doc/UNSUPPORTED_CVE_LIST.md
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
# Unsupported CVEs
|
||||
|
||||
This document lists transient execution CVEs that have been evaluated and determined to be **out of scope** for this tool. See the [Which rules are governing the support of a CVE in this tool?](dist/FAQ.md#which-rules-are-governing-the-support-of-a-cve-in-this-tool) section in the FAQ for the general policy.
|
||||
|
||||
CVEs are grouped by reason for exclusion:
|
||||
|
||||
- [Already covered by an existing CVE check](#already-covered-by-an-existing-cve-check) — subvariants or subsets whose mitigations are already detected under a parent CVE.
|
||||
- [No kernel or microcode mitigations to check](#no-kernel-or-microcode-mitigations-to-check) — no fix has been issued, or the mitigation is not detectable by this tool.
|
||||
- [Not a transient/speculative execution vulnerability](#not-a-transientspeculative-execution-vulnerability) — wrong vulnerability class entirely.
|
||||
|
||||
---
|
||||
|
||||
# Already covered by an existing CVE check
|
||||
|
||||
These CVEs are subvariants or subsets of vulnerabilities already implemented in the tool. Their mitigations are detected as part of the parent CVE's checks.
|
||||
|
||||
## CVE-2018-3693 — Bounds Check Bypass Store (Spectre v1.1)
|
||||
|
||||
- **Issue:** [#236](https://github.com/speed47/spectre-meltdown-checker/issues/236)
|
||||
- **Red Hat advisory:** [Speculative Store Bypass / Bounds Check Bypass (CVE-2018-3693)](https://access.redhat.com/solutions/3523601)
|
||||
- **CVSS:** 5.6 (Medium)
|
||||
- **Covered by:** CVE-2017-5753 (Spectre V1)
|
||||
|
||||
A subvariant of Spectre V1 where speculative store operations can write beyond validated buffer boundaries before the bounds check resolves, allowing an attacker to alter cache state and leak information via side channels.
|
||||
|
||||
**Why out of scope:** The mitigations are identical to CVE-2017-5753 (Spectre V1): `lfence` instructions after bounds checks and `array_index_nospec()` barriers in kernel code. There is no separate sysfs entry, no new CPU feature flag, and no distinct microcode change. This tool's existing CVE-2017-5753 checks already detect these mitigations (`__user pointer sanitization`, `usercopy/swapgs barriers`), so CVE-2018-3693 is fully covered as part of Spectre V1.
|
||||
|
||||
## CVE-2018-15572 — SpectreRSB (Return Stack Buffer)
|
||||
|
||||
- **Issue:** [#224](https://github.com/speed47/spectre-meltdown-checker/issues/224)
|
||||
- **Research paper:** [Spectre Returns! Speculation Attacks using the Return Stack Buffer (WOOT'18)](https://arxiv.org/abs/1807.07940)
|
||||
- **Kernel fix:** [commit fdf82a7856b3](https://github.com/torvalds/linux/commit/fdf82a7856b32d905c39afc85e34364491e46346) (Linux 4.18.1)
|
||||
- **CVSS:** 6.5 (Medium)
|
||||
- **Covered by:** CVE-2017-5715 (Spectre V2)
|
||||
|
||||
The `spectre_v2_select_mitigation` function in the Linux kernel before 4.18.1 did not always fill the RSB upon a context switch, allowing userspace-to-userspace SpectreRSB attacks on Skylake+ CPUs where an empty RSB falls back to the BTB.
|
||||
|
||||
**Why out of scope:** This CVE is a Spectre V2 mitigation gap (missing RSB filling on context switch), not a distinct hardware vulnerability. It is already fully covered by this tool's CVE-2017-5715 (Spectre V2) checks, which detect whether the kernel performs RSB filling on CPUs vulnerable to RSB underflow (Skylake+ and RSBA-capable CPUs). A missing RSB fill is flagged as a caveat ("RSB filling missing on Skylake+") in the Spectre V2 verdict.
|
||||
|
||||
## CVE-2019-1125 — Spectre SWAPGS gadget
|
||||
|
||||
- **Issue:** [#301](https://github.com/speed47/spectre-meltdown-checker/issues/301)
|
||||
- **Kernel fix:** [commit 18ec54fdd6d1](https://github.com/torvalds/linux/commit/18ec54fdd6d18d92025af097cd042a75cf0ea24c) (Linux 5.3)
|
||||
- **CVSS:** 5.6 (Medium)
|
||||
- **Covered by:** CVE-2017-5753 (Spectre V1)
|
||||
|
||||
A Spectre V1 subvariant where the `SWAPGS` instruction can be speculatively executed on x86 CPUs, allowing an attacker to leak kernel memory via a side channel on the GS segment base value.
|
||||
|
||||
**Why out of scope:** This is a Spectre V1 subvariant whose mitigation (SWAPGS barriers) shares the same sysfs entry as CVE-2017-5753. This tool's existing CVE-2017-5753 checks already detect SWAPGS barriers: a mitigated kernel reports `"Mitigation: usercopy/swapgs barriers and __user pointer sanitization"`, while a kernel lacking the fix reports `"Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers"`. CVE-2019-1125 is therefore fully covered as part of Spectre V1.
|
||||
|
||||
## CVE-2021-26341 — AMD Straight-Line Speculation (direct branches)
|
||||
|
||||
- **Bulletin:** [AMD-SB-1026](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-1026.html)
|
||||
- **Affected CPUs:** AMD Zen 1, Zen 2
|
||||
- **CVSS:** 6.5 (Medium)
|
||||
- **Covered by:** CVE-0000-0001 (SLS supplementary check)
|
||||
|
||||
AMD Zen 1/Zen 2 CPUs may transiently execute instructions beyond unconditional direct branches (JMP, CALL), potentially allowing information disclosure via side channels.
|
||||
|
||||
**Why out of scope:** This is the AMD-specific direct-branch subset of the broader Straight-Line Speculation (SLS) class. The kernel mitigates it via `CONFIG_MITIGATION_SLS` (formerly `CONFIG_SLS`), which enables the GCC flag `-mharden-sls=all` to insert INT3 after unconditional control flow instructions. Since this is a compile-time-only mitigation with no sysfs interface, no MSR, and no per-CVE CPU feature flag, it cannot be checked using the standard CVE framework. A supplementary SLS check is available via `--extra` mode, which covers this CVE's mitigation as well.
|
||||
|
||||
## CVE-2020-13844 — ARM Straight-Line Speculation
|
||||
|
||||
- **Advisory:** [ARM Developer Security Update (June 2020)](https://developer.arm.com/Arm%20Security%20Center/Speculative%20Processor%20Vulnerability)
|
||||
- **Affected CPUs:** Cortex-A32, A34, A35, A53, A57, A72, A73, and broadly all speculative Armv8-A cores
|
||||
- **CVSS:** 5.5 (Medium)
|
||||
- **Covered by:** CVE-0000-0001 (SLS supplementary check)
|
||||
|
||||
ARM processors may speculatively execute instructions past unconditional control flow changes (RET, BR, BLR). GCC and Clang support `-mharden-sls=all` for aarch64, but the Linux kernel never merged the patches to enable it: a `CONFIG_HARDEN_SLS_ALL` series was submitted in 2021 but rejected upstream.
|
||||
|
||||
**Why out of scope:** This is the ARM-specific subset of the broader Straight-Line Speculation (SLS) class. The supplementary SLS check available via `--extra` mode detects affected ARM CPU models and reports that no kernel mitigation is currently available.
|
||||
|
||||
## CVE-2024-2201 — Native BHI (Branch History Injection without eBPF)
|
||||
|
||||
- **Issue:** [#491](https://github.com/speed47/spectre-meltdown-checker/issues/491)
|
||||
- **Research:** [InSpectre Gadget / Native BHI (VUSec)](https://www.vusec.net/projects/native-bhi/)
|
||||
- **Intel advisory:** [Branch History Injection (Intel)](https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/branch-history-injection.html)
|
||||
- **Affected CPUs:** Intel CPUs with eIBRS (Ice Lake+, 10th gen+, and virtualized Intel guests)
|
||||
- **CVSS:** 4.7 (Medium)
|
||||
- **Covered by:** CVE-2017-5715 (Spectre V2)
|
||||
|
||||
VUSec researchers demonstrated that the original BHI mitigation (disabling unprivileged eBPF) was insufficient: 1,511 native kernel gadgets exist that allow exploiting Branch History Injection without eBPF, leaking arbitrary kernel memory at ~3.5 kB/sec on Intel CPUs.
|
||||
|
||||
**Why out of scope:** CVE-2024-2201 is not a new hardware vulnerability — it is the same BHI hardware bug as CVE-2022-0002, but proves that eBPF restriction alone was never sufficient. The required mitigations are identical: `BHI_DIS_S` hardware control (MSR `IA32_SPEC_CTRL` bit 10), software BHB clearing loop at syscall entry and VM exit, or retpoline with RRSBA disabled. These are all already detected by this tool's CVE-2017-5715 (Spectre V2) checks, which parse the `BHI:` suffix from `/sys/devices/system/cpu/vulnerabilities/spectre_v2` and check for `CONFIG_MITIGATION_SPECTRE_BHI` in no-runtime mode. No new sysfs entry, MSR, kernel config option, or boot parameter was introduced for this CVE.
|
||||
|
||||
## CVE-2020-0549 — L1D Eviction Sampling (CacheOut)
|
||||
|
||||
- **Issue:** [#341](https://github.com/speed47/spectre-meltdown-checker/issues/341)
|
||||
- **Advisory:** [INTEL-SA-00329](https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/l1d-eviction-sampling.html)
|
||||
- **Affected CPUs:** Intel Skylake through 10th gen (Tiger Lake+ not affected)
|
||||
- **CVSS:** 6.5 (Medium)
|
||||
- **Covered by:** CVE-2018-12126 / CVE-2018-12127 / CVE-2018-12130 / CVE-2019-11091 (MDS) and CVE-2018-3646 (L1TF)
|
||||
|
||||
An Intel-specific data leakage vulnerability where L1 data cache evictions can be exploited in combination with MDS or TAA side channels to leak data across security boundaries.
|
||||
|
||||
**Why out of scope:** The June 2020 microcode update that addresses this CVE does not introduce any new MSR bits or CPUID flags — it reuses the existing MD_CLEAR (`CPUID.7.0:EDX[10]`) and L1D_FLUSH (`MSR_IA32_FLUSH_CMD`, 0x10B) infrastructure already deployed for MDS and L1TF. The Linux kernel has no dedicated sysfs entry in `/sys/devices/system/cpu/vulnerabilities/` for this CVE; instead, it provides an opt-in per-task L1D flush via `prctl(PR_SPEC_L1D_FLUSH)` and the `l1d_flush=on` boot parameter, which piggyback on the same L1D flush mechanism checked by the existing L1TF and MDS vulnerability modules. In practice, a system with up-to-date microcode and MDS/L1TF mitigations in place is already protected against L1D Eviction Sampling.
|
||||
|
||||
## CVE-2025-20623 — Shared Microarchitectural Predictor State (10th Gen Intel)
|
||||
|
||||
- **Advisory:** [INTEL-SA-01247](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-01247.html)
|
||||
- **Affected CPUs:** Intel 10th Generation Core Processors only
|
||||
- **CVSS:** 5.6 (Medium)
|
||||
- **Covered by:** CVE-2024-45332 (BPI)
|
||||
|
||||
Shared microarchitectural predictor state on 10th generation Intel CPUs may allow information disclosure.
|
||||
|
||||
**Why out of scope:** Very narrow scope (single CPU generation). Mitigated by the same microcode update as CVE-2024-45332 (BPI) and handled through the existing Spectre V2 framework. No dedicated sysfs entry or kernel mitigation beyond what BPI already provides.
|
||||
|
||||
## CVE-2025-24495 — Lion Cove BPU Initialization
|
||||
|
||||
- **Advisory:** [INTEL-SA-01322](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-01322.html)
|
||||
- **Research:** [Training Solo (VUSec)](https://www.vusec.net/projects/training-solo/)
|
||||
- **Affected CPUs:** Intel Core Ultra with Lion Cove core only (Lunar Lake, Arrow Lake)
|
||||
- **CVSS:** 6.8 (Medium, CVSS v4)
|
||||
- **Covered by:** CVE-2024-28956 (ITS)
|
||||
|
||||
A branch predictor initialization issue specific to Intel's Lion Cove microarchitecture, discovered as part of the "Training Solo" research.
|
||||
|
||||
**Why out of scope:** This is a subset of the ITS (Indirect Target Selection) vulnerability (CVE-2024-28956). It shares the same sysfs entry (`/sys/devices/system/cpu/vulnerabilities/indirect_target_selection`) and kernel mitigation framework. Since ITS (CVE-2024-28956) is implemented in this tool, Lion Cove BPU is already covered automatically.
|
||||
|
||||
---
|
||||
|
||||
# No kernel or microcode mitigations to check
|
||||
|
||||
These CVEs are real vulnerabilities, but no kernel or microcode fix has been issued, the mitigation is delegated to individual software, or the fix is not detectable by this tool.
|
||||
|
||||
## CVE-2018-9056 — BranchScope
|
||||
|
||||
- **Issue:** [#169](https://github.com/speed47/spectre-meltdown-checker/issues/169)
|
||||
- **Research paper:** [BranchScope (ASPLOS 2018)](http://www.cs.ucr.edu/~nael/pubs/asplos18.pdf)
|
||||
- **Red Hat bug:** [#1561794](https://bugzilla.redhat.com/show_bug.cgi?id=1561794)
|
||||
- **CVSS:** 5.6 (Medium)
|
||||
|
||||
A speculative execution attack exploiting the directional branch predictor, allowing an attacker to infer data by manipulating the shared branch prediction state (pattern history table). Initially demonstrated on Intel processors.
|
||||
|
||||
**Why out of scope:** No kernel or microcode mitigations have been issued. Red Hat closed their tracking bug as "CLOSED CANTFIX", concluding that "this is a hardware processor issue, not a Linux kernel flaw" and that "it is specific to a target software which uses sensitive information in branching expressions." The mitigation responsibility falls on individual software to avoid using sensitive data in conditional branches, which is out of the scope of this tool.
|
||||
|
||||
## CVE-2019-15902 — Spectre V1 backport regression
|
||||
|
||||
- **Issue:** [#304](https://github.com/speed47/spectre-meltdown-checker/issues/304)
|
||||
- **CVSS:** 5.6 (Medium)
|
||||
|
||||
A backporting mistake in Linux stable/longterm kernel versions (4.4.x through 4.4.190, 4.9.x through 4.9.190, 4.14.x through 4.14.141, 4.19.x through 4.19.69, and 5.2.x through 5.2.11) swapped two code lines in `ptrace_get_debugreg()`, placing the `array_index_nospec()` call after the array access instead of before, reintroducing a Spectre V1 vulnerability.
|
||||
|
||||
**Why out of scope:** This is a kernel bug (bad backport), not a hardware vulnerability. The flawed code is not detectable on a running kernel without hardcoding kernel version ranges, which is against this tool's design principles. As the tool author noted: "it's going to be almost impossible to detect it on a running kernel."
|
||||
|
||||
## CVE-2020-12965 — Transient Execution of Non-Canonical Accesses (SLAM)
|
||||
|
||||
- **Issue:** [#478](https://github.com/speed47/spectre-meltdown-checker/issues/478)
|
||||
- **Bulletin:** [AMD-SB-1010](https://www.amd.com/en/corporate/product-security/bulletin/amd-sb-1010)
|
||||
- **Research paper:** [SLAM (VUSec)](https://www.vusec.net/projects/slam/)
|
||||
- **CVSS:** 7.5 (High)
|
||||
|
||||
AMD CPUs may transiently execute non-canonical loads and stores using only the lower 48 address bits, potentially resulting in data leakage. The SLAM research (2023) demonstrated that this could be exploited on existing AMD Zen+/Zen2 CPUs and could also affect future CPUs with Intel LAM, AMD UAI, or ARM TBI features.
|
||||
|
||||
**Why out of scope:** AMD's mitigation guidance is for software vendors to "analyze their code for any potential vulnerabilities" and insert LFENCE or use existing speculation mitigation techniques in their own code. No microcode or kernel-level mitigations have been issued. The responsibility falls on individual software, not on the kernel or firmware, leaving nothing for this script to check.
|
||||
|
||||
## CVE-2020-24511 — Domain-Type Confusion (IBRS Scope)
|
||||
|
||||
- **Issue:** [#409](https://github.com/speed47/spectre-meltdown-checker/issues/409)
|
||||
- **Advisory:** [INTEL-SA-00464](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00464.html)
|
||||
- **Affected CPUs:** Intel Skylake through Comet Lake (different steppings; see advisory for details)
|
||||
- **CVSS:** 6.5 (Medium)
|
||||
|
||||
Improper isolation of shared resources in some Intel processors allows an authenticated user to potentially enable information disclosure via local access. Specifically, the Indirect Branch Restricted Speculation (IBRS) mitigation may not be fully applied after certain privilege-level transitions, allowing residual branch predictions to cross security boundaries.
|
||||
|
||||
**Why out of scope:** The mitigation is exclusively a microcode update (released June 2021) with no corresponding Linux kernel sysfs entry in `/sys/devices/system/cpu/vulnerabilities/`, no new CPUID bit, no new MSR, and no kernel configuration option. The only way to detect the fix would be to maintain a per-CPU-stepping minimum microcode version lookup table, which is brittle and high-maintenance. Additionally, Intel dropped microcode support for Sandy Bridge and Ivy Bridge in the same timeframe, leaving those generations permanently unpatched with no mitigation path available.
|
||||
|
||||
## CVE-2020-24512 — Observable Timing Discrepancy (Trivial Data Value)
|
||||
|
||||
- **Issue:** [#409](https://github.com/speed47/spectre-meltdown-checker/issues/409)
|
||||
- **Advisory:** [INTEL-SA-00464](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00464.html)
|
||||
- **Affected CPUs:** Intel Skylake through Tiger Lake (broad scope; see advisory for details)
|
||||
- **CVSS:** 2.8 (Low)
|
||||
|
||||
Observable timing discrepancy in some Intel processors allows an authenticated user to potentially enable information disclosure via local access. Certain cache optimizations treat "trivial data value" cache lines (e.g., all-zero lines) differently from non-trivial lines, creating a timing side channel that can distinguish memory content patterns.
|
||||
|
||||
**Why out of scope:** Like CVE-2020-24511, this is a microcode-only fix with no Linux kernel sysfs entry, no CPUID bit, no MSR, and no kernel configuration option. Detection would require a per-CPU-stepping microcode version lookup table. The vulnerability has low severity (CVSS 2.8) and practical exploitation is limited. Intel dropped microcode support for Sandy Bridge and Ivy Bridge, leaving those generations permanently vulnerable.
|
||||
|
||||
## CVE-2021-26318 — AMD Prefetch Attacks through Power and Time
|
||||
|
||||
- **Issue:** [#412](https://github.com/speed47/spectre-meltdown-checker/issues/412)
|
||||
- **Bulletin:** [AMD-SB-1017](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-1017.html)
|
||||
- **Research paper:** [AMD Prefetch Attacks through Power and Time (USENIX Security '22)](https://www.usenix.org/conference/usenixsecurity22/presentation/lipp)
|
||||
- **CVSS:** 5.5 (Medium)
|
||||
|
||||
The x86 PREFETCH instruction on AMD CPUs leaks timing and power information, enabling a microarchitectural KASLR bypass from unprivileged userspace. The researchers demonstrated kernel address space layout recovery and kernel memory leakage at ~52 B/s using Spectre gadgets.
|
||||
|
||||
**Why out of scope:** AMD acknowledged the research but explicitly stated they are "not recommending any mitigations at this time," as the attack leaks kernel address layout information (KASLR bypass) but does not directly leak kernel data across address space boundaries. KPTI was never enabled on AMD by default in the Linux kernel as a result. No microcode, kernel, or sysfs mitigations have been issued, leaving nothing for this script to check.
|
||||
|
||||
## CVE-2024-7881 — ARM Prefetcher Privilege Escalation
|
||||
|
||||
- **Affected CPUs:** Specific ARM cores only
|
||||
- **CVSS:** 5.1 (Medium)
|
||||
|
||||
The prefetch engine on certain ARM cores can fetch data from privileged memory locations. Mitigation is disabling the affected prefetcher via the `CPUACTLR6_EL1[41]` register bit.
|
||||
|
||||
**Why out of scope:** ARM-specific with very narrow scope and no Linux sysfs integration. The mitigation is a per-core register tweak, not a kernel or microcode update detectable by this tool.
|
||||
|
||||
## CVE-2024-36348 — AMD Transient Scheduler Attack (UMIP bypass)
|
||||
|
||||
- **Bulletin:** [AMD-SB-7029](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7029.html)
|
||||
- **CVSS:** 3.8 (Low)
|
||||
|
||||
A transient execution vulnerability in some AMD processors may allow a user process to speculatively infer CPU configuration registers even when UMIP is enabled.
|
||||
|
||||
**Why out of scope:** AMD has determined that "leakage of CPU Configuration does not result in leakage of sensitive information" and has marked this CVE as "No fix planned" across all affected product lines. No microcode or kernel mitigations have been issued, leaving nothing for this script to check.
|
||||
|
||||
## CVE-2024-36349 — AMD Transient Scheduler Attack (TSC_AUX leak)
|
||||
|
||||
- **Bulletin:** [AMD-SB-7029](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7029.html)
|
||||
- **CVSS:** 3.8 (Low)
|
||||
|
||||
A transient execution vulnerability in some AMD processors may allow a user process to infer TSC_AUX even when such a read is disabled.
|
||||
|
||||
**Why out of scope:** AMD has determined that "leakage of TSC_AUX does not result in leakage of sensitive information" and has marked this CVE as "No fix planned" across all affected product lines. No microcode or kernel mitigations have been issued, leaving nothing for this script to check.
|
||||
|
||||
## No CVE — BlindSide (Speculative Probing)
|
||||
|
||||
- **Issue:** [#374](https://github.com/speed47/spectre-meltdown-checker/issues/374)
|
||||
- **Research paper:** [Speculative Probing: Hacking Blind in the Spectre Era (VUSec, ACM CCS 2020)](https://www.vusec.net/projects/blindside/)
|
||||
- **Red Hat advisory:** [Article 5394291](https://access.redhat.com/articles/5394291)
|
||||
- **Affected CPUs:** All CPUs vulnerable to Spectre V2 (BTB-based speculative execution)
|
||||
|
||||
An attack technique that combines a pre-existing kernel memory corruption bug (e.g., a heap buffer overflow) with speculative execution to perform "Speculative BROP" (Blind Return-Oriented Programming). Instead of crashing the system when probing invalid addresses, BlindSide performs the probing speculatively: faults are suppressed in the speculative domain, and information is leaked via cache timing side channels. This allows an attacker to silently derandomize kernel memory layout and bypass KASLR/FGKASLR without triggering any fault.
|
||||
|
||||
**Why out of scope:** BlindSide is an exploitation technique, not a discrete hardware vulnerability: no CVE was assigned. Red Hat explicitly states it is "not a new flaw, but a new attack." It requires a pre-existing kernel memory corruption bug as a prerequisite, and the speculative execution aspect leverages the same BTB behavior as Spectre V2 (CVE-2017-5715). No dedicated microcode update, kernel config, MSR, CPUID bit, or sysfs entry exists for BlindSide. The closest hardware mitigations (IBPB, IBRS, STIBP, Retpoline) are already covered by this tool's Spectre V2 checks.
|
||||
|
||||
## No CVE — TLBleed (TLB side-channel)
|
||||
|
||||
- **Issue:** [#231](https://github.com/speed47/spectre-meltdown-checker/issues/231)
|
||||
- **Research paper:** [Defeating Cache Side-channel Protections with TLB Attacks (VUSec, USENIX Security '18)](https://www.vusec.net/projects/tlbleed/)
|
||||
- **Red Hat blog:** [Temporal side-channels and you: Understanding TLBleed](https://www.redhat.com/en/blog/temporal-side-channels-and-you-understanding-tlbleed)
|
||||
- **Affected CPUs:** Intel CPUs with Hyper-Threading (demonstrated on Skylake, Coffee Lake, Broadwell Xeon)
|
||||
|
||||
A timing side-channel attack exploiting the shared Translation Lookaside Buffer (TLB) on Intel hyperthreaded CPUs. By using machine learning to analyze TLB hit/miss timing patterns, an attacker co-located on the same physical core can extract cryptographic keys (demonstrated with 99.8% success rate on a 256-bit EdDSA key). OpenBSD disabled Hyper-Threading by default in response.
|
||||
|
||||
**Why out of scope:** No CVE was ever assigned — Intel explicitly declined to request one. Intel stated the attack is "not related to Spectre or Meltdown" and has no plans to issue a microcode fix, pointing to existing constant-time coding practices in cryptographic software as the appropriate defense. No Linux kernel mitigation was ever merged. Red Hat's guidance was limited to operational advice (disable SMT, use CPU pinning) rather than a software fix. The only OS-level response was OpenBSD disabling Hyper-Threading by default. With no CVE, no microcode update, and no kernel mitigation, there is nothing for this script to check.
|
||||
|
||||
---
|
||||
|
||||
# Not a transient/speculative execution vulnerability
|
||||
|
||||
These are hardware flaws but not side-channel or speculative execution issues. They fall outside the vulnerability class this tool is designed to detect.
|
||||
|
||||
## CVE-2019-11157 — Plundervolt (VoltJockey)
|
||||
|
||||
- **Issue:** [#335](https://github.com/speed47/spectre-meltdown-checker/issues/335)
|
||||
- **Advisory:** [INTEL-SA-00289](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00289.html)
|
||||
- **Research:** [Plundervolt (plundervolt.com)](https://plundervolt.com/)
|
||||
- **Affected CPUs:** Intel Core 6th–10th gen (Skylake through Comet Lake) with SGX
|
||||
- **CVSS:** 7.1 (High)
|
||||
|
||||
A voltage fault injection attack where a privileged attacker (ring 0) uses the software-accessible voltage scaling interface to undervolt the CPU during SGX enclave computations, inducing predictable bit flips that compromise enclave integrity and confidentiality. Intel's microcode fix locks down the voltage/frequency scaling MSRs to prevent software-initiated undervolting.
|
||||
|
||||
**Why out of scope:** Not a transient or speculative execution vulnerability — this is a fault injection attack exploiting voltage manipulation, with no side-channel or speculative execution component. It requires ring 0 access and targets SGX enclaves specifically. While Intel issued a microcode update that locks voltage controls, there is no Linux kernel sysfs entry, no CPUID flag, and no kernel-side mitigation to detect. The fix is purely a microcode-level lockdown of voltage scaling registers, which is not exposed in any standard interface this tool can query.
|
||||
|
||||
## CVE-2020-8694 / CVE-2020-8695 — Platypus (RAPL Power Side Channel)
|
||||
|
||||
- **Issue:** [#384](https://github.com/speed47/spectre-meltdown-checker/issues/384)
|
||||
- **Advisory:** [INTEL-SA-00389](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00389.html)
|
||||
- **Research:** [PLATYPUS (platypusattack.com)](https://platypusattack.com/)
|
||||
- **Affected CPUs:** Intel Core (Sandy Bridge+), Intel Xeon (Sandy Bridge-EP+)
|
||||
- **CVSS:** 5.6 (Medium) / 6.5 (Medium)
|
||||
|
||||
A software-based power side-channel attack exploiting Intel's Running Average Power Limit (RAPL) interface. By monitoring energy consumption reported through the `powercap` sysfs interface or the `MSR_RAPL_POWER_UNIT` / `MSR_PKG_ENERGY_STATUS` MSRs, an unprivileged attacker can statistically distinguish instructions and operands, recover AES-NI keys from SGX enclaves, and break kernel ASLR.
|
||||
|
||||
**Why out of scope:** Not a transient or speculative execution vulnerability — this is a power analysis side-channel attack with no speculative execution component. The mitigations (microcode update restricting RAPL energy reporting to privileged access, and kernel restricting the `powercap` sysfs interface) are not exposed via `/sys/devices/system/cpu/vulnerabilities/`. There is no dedicated sysfs vulnerability entry, no CPUID flag, and no kernel configuration option for this tool to check.
|
||||
|
||||
## CVE-2023-31315 — SinkClose (AMD SMM Lock Bypass)
|
||||
|
||||
- **Issue:** [#499](https://github.com/speed47/spectre-meltdown-checker/issues/499)
|
||||
- **Bulletin:** [AMD-SB-7014](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7014.html)
|
||||
- **Research:** [AMD SinkClose (IOActive, DEF CON 32)](https://www.ioactive.com/resources/amd-sinkclose-universal-ring-2-privilege-escalation)
|
||||
- **Affected CPUs:** AMD Zen 1–5 (EPYC, Ryzen, Threadripper, Embedded)
|
||||
- **CVSS:** 7.5 (High)
|
||||
|
||||
Improper validation in a model-specific register (MSR) allows a program with ring 0 (kernel) access to modify System Management Mode (SMM) configuration while SMI lock is enabled, escalating privileges from ring 0 to ring -2 (SMM). AMD provides two mitigation paths: BIOS/AGESA firmware updates (all product lines) and hot-loadable microcode updates (EPYC server processors only).
|
||||
|
||||
**Why out of scope:** Not a transient or speculative execution vulnerability — this is a privilege escalation via MSR manipulation, with no side-channel component. It requires ring 0 access as a prerequisite, fundamentally different from Spectre/Meltdown-class attacks where unprivileged code can leak data across privilege boundaries. There is no Linux kernel sysfs entry and no kernel-side mitigation. Although AMD provides hot-loadable microcode for some EPYC processors, the client and embedded product lines are mitigated only through BIOS firmware updates, which this tool cannot detect.
|
||||
|
||||
## CVE-2024-56161 — EntrySign (AMD Microcode Signature Bypass)
|
||||
|
||||
- **Affected CPUs:** AMD Zen 1-5
|
||||
- **CVSS:** 7.2 (High)
|
||||
|
||||
A weakness in AMD's microcode signature verification (AES-CMAC hash) allows loading arbitrary unsigned microcode with administrator privileges.
|
||||
|
||||
**Why out of scope:** This is a microcode integrity/authentication issue, not a speculative execution vulnerability. It does not involve transient execution side channels and is outside the scope of this tool.
|
||||
|
||||
## CVE-2025-29943 — StackWarp (AMD SEV-SNP)
|
||||
|
||||
- **Affected CPUs:** AMD Zen 1-5
|
||||
- **CVSS:** Low
|
||||
|
||||
Exploits a synchronization failure in the AMD stack engine via an undocumented MSR bit, targeting AMD SEV-SNP confidential VMs. Requires hypervisor-level (ring 0) access.
|
||||
|
||||
**Why out of scope:** Not a transient/speculative execution side channel. This is an architectural attack on AMD SEV-SNP confidential computing that requires hypervisor access, which is outside the threat model of this tool.
|
||||
391
dist/doc/batch_json.md
vendored
Normal file
391
dist/doc/batch_json.md
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
# JSON Output Format
|
||||
|
||||
`--batch json` emits a single, self-contained JSON object that describes the
|
||||
scan environment and the result of every CVE check. You can feed it to your
|
||||
monitoring system, to a SIEM, to a time-series database, you name it.
|
||||
|
||||
```sh
|
||||
sudo ./spectre-meltdown-checker.sh --batch json | jq .
|
||||
```
|
||||
|
||||
## Top-level schema
|
||||
|
||||
```
|
||||
{
|
||||
"meta": { ... }, // Run metadata and flags
|
||||
"system": { ... }, // Kernel and host context
|
||||
"cpu": { ... }, // CPU hardware identification
|
||||
"cpu_microcode": { ... }, // Microcode version and status
|
||||
"vulnerabilities": [ ... ] // One object per checked CVE
|
||||
}
|
||||
```
|
||||
|
||||
`format_version` in `meta` is an integer that will be incremented on
|
||||
backward-incompatible schema changes. The current value is **1**.
|
||||
|
||||
## Section reference
|
||||
|
||||
### `meta`
|
||||
|
||||
Run metadata. Always present.
|
||||
|
||||
| Field | Type | Values | Meaning |
|
||||
|---|---|---|---|
|
||||
| `script_version` | string | e.g. `"25.30.0250400123"` | Script version |
|
||||
| `format_version` | integer | `1` | JSON schema version; incremented on breaking changes |
|
||||
| `timestamp` | string | ISO 8601 UTC, e.g. `"2025-04-07T12:00:00Z"` | When the scan started |
|
||||
| `os` | string | e.g. `"Linux"`, `"FreeBSD"` | Output of `uname -s` |
|
||||
| `mode` | string | `"live"` / `"no-runtime"` / `"no-hw"` / `"hw-only"` | Operating mode (see [modes](README.md#operating-modes)) |
|
||||
| `run_as_root` | boolean | | Whether the script ran as root. Non-root scans skip MSR reads and may miss mitigations |
|
||||
| `reduced_accuracy` | boolean | | Kernel image, config, or System.map was missing; some checks fall back to weaker heuristics |
|
||||
| `paranoid` | boolean | | `--paranoid` mode: stricter criteria (e.g. requires SMT disabled, IBPB always-on) |
|
||||
| `sysfs_only` | boolean | | `--sysfs-only`: only the kernel's own sysfs report was used, not independent detection |
|
||||
| `extra` | boolean | | `--extra`: additional experimental checks were enabled |
|
||||
| `mocked` | boolean | | One or more CPU values were overridden for testing. Results do **not** reflect the real system |
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
"meta": {
|
||||
"script_version": "25.30.025040123",
|
||||
"format_version": 1,
|
||||
"timestamp": "2025-04-07T12:00:00Z",
|
||||
"os": "Linux",
|
||||
"mode": "live",
|
||||
"run_as_root": true,
|
||||
"reduced_accuracy": false,
|
||||
"paranoid": false,
|
||||
"sysfs_only": false,
|
||||
"extra": false,
|
||||
"mocked": false
|
||||
}
|
||||
```
|
||||
|
||||
**Important flags for fleet operators:**
|
||||
|
||||
- `run_as_root: false` means the scan was incomplete. Treat results as lower
|
||||
confidence. Alert separately: results may be missing or wrong.
|
||||
- `sysfs_only: true` means the script trusted the kernel's self-report without
|
||||
independent verification. Some older kernels misreport their mitigation
|
||||
status. Do not use `--sysfs-only` for production fleet monitoring.
|
||||
- `paranoid: true` raises the bar: only compare `vulnerable` counts across
|
||||
hosts with the same `paranoid` value.
|
||||
- `mocked: true` must never appear on a production host. If it does, every
|
||||
downstream result is fabricated.
|
||||
|
||||
---
|
||||
|
||||
### `system`
|
||||
|
||||
Kernel and host environment. Always present.
|
||||
|
||||
| Field | Type | Values | Meaning |
|
||||
|---|---|---|---|
|
||||
| `kernel_release` | string \| null | e.g. `"6.1.0-21-amd64"` | Output of `uname -r` (null in no-runtime, no-hw, and hw-only modes) |
|
||||
| `kernel_version` | string \| null | e.g. `"#1 SMP Debian …"` | Output of `uname -v` (null in no-runtime, no-hw, and hw-only modes) |
|
||||
| `kernel_arch` | string \| null | e.g. `"x86_64"` | Output of `uname -m` (null in no-runtime, no-hw, and hw-only modes) |
|
||||
| `kernel_image` | string \| null | e.g. `"/boot/vmlinuz-6.1.0-21-amd64"` | Path passed via `--kernel`, or null if not specified |
|
||||
| `kernel_config` | string \| null | | Path passed via `--config`, or null |
|
||||
| `kernel_version_string` | string \| null | | Kernel version banner extracted from the image |
|
||||
| `kernel_cmdline` | string \| null | | Kernel command line from `/proc/cmdline` (live mode) or the image |
|
||||
| `cpu_count` | integer \| null | | Number of logical CPUs detected |
|
||||
| `smt_enabled` | boolean \| null | | Whether SMT (HyperThreading) is currently active; null if undeterminable |
|
||||
| `hypervisor_host` | boolean \| null | | Whether this machine is detected as a VM host (running KVM, Xen, VMware, etc.) |
|
||||
| `hypervisor_host_reason` | string \| null | | Human-readable explanation of why `hypervisor_host` was set |
|
||||
|
||||
**`hypervisor_host`** materially changes the risk profile of several CVEs.
|
||||
L1TF (CVE-2018-3646) and MDS (CVE-2018-12126/12130/12127) are significantly
|
||||
more severe on hypervisor hosts because they can be exploited across VM
|
||||
boundaries by a malicious guest. Prioritise remediation where
|
||||
`hypervisor_host: true`.
|
||||
|
||||
---
|
||||
|
||||
### `cpu`
|
||||
|
||||
CPU hardware identification. `null` when `--no-hw` is active.
|
||||
|
||||
The object uses `arch` as a discriminator: `"x86"` for Intel/AMD/Hygon CPUs,
|
||||
`"arm"` for ARM/Cavium/Phytium. Arch-specific fields live under a matching
|
||||
sub-object (`cpu.x86` or `cpu.arm`), so consumers never see irrelevant null
|
||||
fields from the other architecture.
|
||||
|
||||
#### Common fields
|
||||
|
||||
| Field | Type | Values | Meaning |
|
||||
|---|---|---|---|
|
||||
| `arch` | string | `"x86"` / `"arm"` | CPU architecture family; determines which sub-object is present |
|
||||
| `vendor` | string \| null | e.g. `"GenuineIntel"`, `"ARM"` | CPU vendor string |
|
||||
| `friendly_name` | string \| null | e.g. `"Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz"` | Human-readable CPU model |
|
||||
|
||||
#### `cpu.x86` (present when `arch == "x86"`)
|
||||
|
||||
| Field | Type | Values | Meaning |
|
||||
|---|---|---|---|
|
||||
| `family` | integer \| null | | CPU family number |
|
||||
| `model` | integer \| null | | CPU model number |
|
||||
| `stepping` | integer \| null | | CPU stepping number |
|
||||
| `cpuid` | string \| null | hex, e.g. `"0x000906ed"` | Full CPUID leaf 1 EAX value |
|
||||
| `platform_id` | integer \| null | | Intel platform ID (from MSR 0x17); null on AMD |
|
||||
| `hybrid` | boolean \| null | | Whether this is a hybrid CPU (P-cores + E-cores, e.g. Alder Lake) |
|
||||
| `codename` | string \| null | e.g. `"Coffee Lake"` | Intel CPU codename; null on AMD |
|
||||
| `capabilities` | object | | CPU feature flags (see below) |
|
||||
|
||||
#### `cpu.arm` (present when `arch == "arm"`)
|
||||
|
||||
| Field | Type | Values | Meaning |
|
||||
|---|---|---|---|
|
||||
| `part_list` | string \| null | e.g. `"0xd0b 0xd05"` | Space-separated ARM part numbers across cores (big.LITTLE may have several) |
|
||||
| `arch_list` | string \| null | e.g. `"8 8"` | Space-separated ARM architecture levels across cores |
|
||||
| `capabilities` | object | | ARM-specific capability flags (currently empty; reserved for future use) |
|
||||
|
||||
#### `cpu.x86.capabilities`
|
||||
|
||||
Each capability is a **tri-state**: `true` (present), `false` (absent), or
|
||||
`null` (not applicable or could not be read, e.g. when not root or on AMD for
|
||||
Intel-specific features).
|
||||
|
||||
| Capability | Meaning |
|
||||
|---|---|
|
||||
| `spec_ctrl` | SPEC_CTRL MSR (Intel: ibrs + ibpb via WRMSR; required for many mitigations) |
|
||||
| `ibrs` | Indirect Branch Restricted Speculation |
|
||||
| `ibpb` | Indirect Branch Prediction Barrier |
|
||||
| `ibpb_ret` | IBPB on return (enhanced form) |
|
||||
| `stibp` | Single Thread Indirect Branch Predictors |
|
||||
| `ssbd` | Speculative Store Bypass Disable |
|
||||
| `l1d_flush` | L1D cache flush instruction |
|
||||
| `md_clear` | VERW clears CPU buffers (MDS mitigation) |
|
||||
| `arch_capabilities` | IA32_ARCH_CAPABILITIES MSR is present |
|
||||
| `rdcl_no` | Not susceptible to RDCL (Meltdown-like attacks) |
|
||||
| `ibrs_all` | Enhanced IBRS always-on mode supported |
|
||||
| `rsba` | RSB may use return predictions from outside the RSB |
|
||||
| `l1dflush_no` | Not susceptible to L1D flush side-channel |
|
||||
| `ssb_no` | Not susceptible to Speculative Store Bypass |
|
||||
| `mds_no` | Not susceptible to MDS |
|
||||
| `taa_no` | Not susceptible to TSX Asynchronous Abort |
|
||||
| `pschange_msc_no` | Page-size-change MSC not susceptible |
|
||||
| `tsx_ctrl_msr` | TSX_CTRL MSR is present |
|
||||
| `tsx_ctrl_rtm_disable` | RTM disabled via TSX_CTRL |
|
||||
| `tsx_ctrl_cpuid_clear` | CPUID HLE/RTM bits cleared via TSX_CTRL |
|
||||
| `gds_ctrl` | GDS_CTRL MSR present (GDS mitigation control) |
|
||||
| `gds_no` | Not susceptible to Gather Data Sampling |
|
||||
| `gds_mitg_dis` | GDS mitigation disabled |
|
||||
| `gds_mitg_lock` | GDS mitigation locked |
|
||||
| `rfds_no` | Not susceptible to Register File Data Sampling |
|
||||
| `rfds_clear` | VERW clears register file stale data |
|
||||
| `its_no` | Not susceptible to Indirect Target Selection |
|
||||
| `sbdr_ssdp_no` | Not susceptible to SBDR/SSDP |
|
||||
| `fbsdp_no` | Not susceptible to FBSDP |
|
||||
| `psdp_no` | Not susceptible to PSDP |
|
||||
| `fb_clear` | Fill buffer cleared on idle/C6 |
|
||||
| `rtm` | Restricted Transactional Memory (TSX RTM) present |
|
||||
| `tsx_force_abort` | TSX_FORCE_ABORT MSR present |
|
||||
| `tsx_force_abort_rtm_disable` | RTM disabled via TSX_FORCE_ABORT |
|
||||
| `tsx_force_abort_cpuid_clear` | CPUID RTM cleared via TSX_FORCE_ABORT |
|
||||
| `sgx` | Software Guard Extensions present |
|
||||
| `srbds` | SRBDS affected |
|
||||
| `srbds_on` | SRBDS mitigation active |
|
||||
| `amd_ssb_no` | AMD: not susceptible to Speculative Store Bypass |
|
||||
| `hygon_ssb_no` | Hygon: not susceptible to Speculative Store Bypass |
|
||||
| `ipred` | Indirect Predictor Barrier support |
|
||||
| `rrsba` | Restricted RSB Alternate (Intel Retbleed mitigation) |
|
||||
| `bhi` | Branch History Injection mitigation support |
|
||||
| `tsa_sq_no` | Not susceptible to TSA-SQ |
|
||||
| `tsa_l1_no` | Not susceptible to TSA-L1 |
|
||||
| `verw_clear` | VERW clears CPU buffers |
|
||||
| `autoibrs` | AMD AutoIBRS (equivalent to enhanced IBRS on Intel) |
|
||||
| `sbpb` | Selective Branch Predictor Barrier (AMD Inception mitigation) |
|
||||
| `avx2` | AVX2 supported (relevant to Downfall / GDS) |
|
||||
| `avx512` | AVX-512 supported (relevant to Downfall / GDS) |
|
||||
|
||||
---
|
||||
|
||||
### `cpu_microcode`
|
||||
|
||||
Microcode version and status. `null` under the same conditions as `cpu`.
|
||||
|
||||
| Field | Type | Values | Meaning |
|
||||
|---|---|---|---|
|
||||
| `installed_version` | string \| null | hex, e.g. `"0xf4"` | Currently running microcode revision |
|
||||
| `latest_version` | string \| null | hex | Latest known-good version in the firmware database; null if CPU is not in the database |
|
||||
| `microcode_up_to_date` | boolean \| null | | Whether `installed_version == latest_version`; null if either is unavailable |
|
||||
| `is_blacklisted` | boolean | | Whether the installed microcode is known to cause instability and must be rolled back |
|
||||
| `message` | string \| null | | Human-readable note from the firmware database (e.g. changelog excerpt) |
|
||||
| `db_source` | string \| null | | Which database was used (e.g. `"Intel-SA"`, `"MCExtractor"`) |
|
||||
| `db_info` | string \| null | | Database revision or date |
|
||||
|
||||
**`is_blacklisted: true`** means the installed microcode is known to cause
|
||||
system instability or incorrect behaviour. Treat this as a P1 incident: roll
|
||||
back to the previous microcode immediately.
|
||||
|
||||
**`microcode_up_to_date: false`** means a newer microcode is available. This
|
||||
does not necessarily mean the system is vulnerable (the current microcode may
|
||||
still include all required mitigations), but warrants investigation.
|
||||
|
||||
---
|
||||
|
||||
### `vulnerabilities`
|
||||
|
||||
Array of CVE check results. One object per checked CVE, in check order.
|
||||
Empty array (`[]`) if no CVEs were checked (unusual; would require `--cve`
|
||||
with an unknown CVE ID).
|
||||
|
||||
| Field | Type | Values | Meaning |
|
||||
|---|---|---|---|
|
||||
| `cve` | string | e.g. `"CVE-2017-5753"` | CVE identifier |
|
||||
| `name` | string | e.g. `"SPECTRE VARIANT 1"` | Short key name used in batch formats |
|
||||
| `aliases` | string \| null | e.g. `"Spectre Variant 1, bounds check bypass"` | Full name including all known aliases |
|
||||
| `cpu_affected` | boolean | | Whether this CPU's hardware design is affected by this CVE |
|
||||
| `status` | string | `"OK"` / `"VULN"` / `"UNK"` | Check outcome (see below) |
|
||||
| `vulnerable` | boolean \| null | `false` / `true` / `null` | `false`=OK, `true`=VULN, `null`=UNK |
|
||||
| `info` | string | | Human-readable description of the specific mitigation state or reason |
|
||||
| `sysfs_status` | string \| null | `"OK"` / `"VULN"` / `"UNK"` / null | Status as reported by the kernel via `/sys/devices/system/cpu/vulnerabilities/`; null if sysfs was not consulted for this CVE |
|
||||
| `sysfs_message` | string \| null | | Raw text from the sysfs file (e.g. `"Mitigation: PTI"`); null if sysfs was not consulted |
|
||||
|
||||
#### Status values
|
||||
|
||||
| `status` | `vulnerable` | Meaning |
|
||||
|---|---|---|
|
||||
| `"OK"` | `false` | CPU is unaffected by design, or all required mitigations are in place |
|
||||
| `"VULN"` | `true` | CPU is affected and mitigations are missing or insufficient |
|
||||
| `"UNK"` | `null` | The script could not determine the status (missing kernel info, insufficient privileges, or no detection logic for this platform) |
|
||||
|
||||
#### `cpu_affected` explained
|
||||
|
||||
`cpu_affected: false` with `status: "OK"` means the CPU hardware is
|
||||
architecturally immune, no patch was ever needed.
|
||||
|
||||
`cpu_affected: true` with `status: "OK"` means the hardware has the weakness
|
||||
but all required mitigations (kernel, microcode, or both) are in place.
|
||||
|
||||
This distinction matters for fleet auditing: filter on `cpu_affected: true` to
|
||||
see only systems where mitigation effort was actually required and confirmed.
|
||||
|
||||
#### `sysfs_status` vs `status`
|
||||
|
||||
`sysfs_status` is the raw kernel self-report. `status` is the script's
|
||||
independent assessment, which may differ:
|
||||
|
||||
- The script may **upgrade** a sysfs `"VULN"` to `"OK"` when it detects a
|
||||
silent backport that the kernel doesn't know about.
|
||||
- The script may **downgrade** a sysfs `"OK"` to `"VULN"` when it detects an
|
||||
incomplete mitigation the kernel doesn't flag (e.g. L1TF on a hypervisor
|
||||
host with SMT still enabled, or TSA in `user` mode on a VMM host).
|
||||
- `sysfs_status` is `null` when the kernel has no sysfs entry for this CVE
|
||||
(older kernels, or CVEs not yet tracked by the kernel).
|
||||
|
||||
Always use `status` / `vulnerable` for alerting. Use `sysfs_status` for
|
||||
diagnostics and audit trails.
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"cve": "CVE-2017-5715",
|
||||
"name": "SPECTRE VARIANT 2",
|
||||
"aliases": "Spectre Variant 2, branch target injection",
|
||||
"cpu_affected": true,
|
||||
"status": "OK",
|
||||
"vulnerable": false,
|
||||
"info": "Full generic retpoline is mitigating the vulnerability",
|
||||
"sysfs_status": "OK",
|
||||
"sysfs_message": "Mitigation: Retpolines; IBPB: conditional; IBRS_FW; STIBP: conditional; RSB filling; PBRSB-eIBRS: Not affected; BHI: Not affected"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exit codes
|
||||
|
||||
The script exits with:
|
||||
|
||||
| Code | Meaning |
|
||||
|---|---|
|
||||
| `0` | All checked CVEs are `OK` |
|
||||
| `2` | At least one CVE is `VULN` |
|
||||
| `3` | No CVEs are `VULN`, but at least one is `UNK` |
|
||||
|
||||
These exit codes are the same in all batch modes and in interactive mode.
|
||||
Use them in combination with the JSON body for reliable alerting.
|
||||
|
||||
---
|
||||
|
||||
## Caveats and edge cases
|
||||
|
||||
**No-runtime mode (`--no-runtime`)**
|
||||
`system.kernel_release`, `kernel_version`, and `kernel_arch` are null (those
|
||||
come from `uname`, which reports the running kernel, not the inspected one).
|
||||
`meta.mode: "no-runtime"` signals this. `system.kernel_image` and
|
||||
`system.kernel_version_string` carry the inspected image path and banner
|
||||
instead.
|
||||
|
||||
**No-hardware mode (`--no-hw`)**
|
||||
`cpu` and `cpu_microcode` are null. CVE checks that rely on hardware
|
||||
capability detection (`cap_*` flags, MSR reads) will report `status: "UNK"`.
|
||||
`cpu_affected` will be `false` for all CVEs (cannot determine affection without
|
||||
hardware info). `meta.mode: "no-hw"` signals this.
|
||||
|
||||
**Hardware-only mode (`--hw-only`)**
|
||||
Only CPU information and per-CVE affectedness are reported. No kernel
|
||||
inspection is performed, so vulnerability mitigations are not checked.
|
||||
`meta.mode: "hw-only"` signals this.
|
||||
|
||||
**`--sysfs-only`**
|
||||
The script trusts the kernel's sysfs report without running independent
|
||||
detection. `meta.sysfs_only: true` flags this. Some older kernels misreport
|
||||
their status. Do not use for production fleet monitoring.
|
||||
|
||||
**`--paranoid`**
|
||||
Enables defense-in-depth checks beyond the security community consensus.
|
||||
A `status: "OK"` under `paranoid: true` means a higher bar was met. Do not
|
||||
compare results across hosts with different `paranoid` values.
|
||||
|
||||
**`reduced_accuracy`**
|
||||
Set when the kernel image, config file, or System.map could not be read.
|
||||
Some checks fall back to weaker heuristics and may report `"UNK"` for CVEs
|
||||
that are actually mitigated.
|
||||
|
||||
**Non-x86 architectures (ARM, ARM64)**
|
||||
On ARM, `cpu.arch` is `"arm"` and the `cpu.arm` sub-object carries `part_list`
|
||||
and `arch_list`. The x86-specific sub-object is absent (no null noise).
|
||||
`cpu.arm.capabilities` is currently empty; ARM-specific flags will be added
|
||||
there as needed.
|
||||
|
||||
**`mocked: true`**
|
||||
Must never appear on a production host. If it does, the results are
|
||||
fabricated and every downstream alert is unreliable.
|
||||
|
||||
---
|
||||
|
||||
## Schema stability
|
||||
|
||||
`meta.format_version` is incremented on backward-incompatible changes (field
|
||||
removal or type change). Additive changes (new fields) do not increment the
|
||||
version; consumers must tolerate unknown fields.
|
||||
|
||||
Recommended practice: check `format_version == 1` at parse time and reject
|
||||
or alert on any other value until you have tested compatibility with the new
|
||||
version.
|
||||
|
||||
---
|
||||
|
||||
## Migration from `json-terse`
|
||||
|
||||
The legacy `--batch json-terse` format emits a flat array of objects:
|
||||
|
||||
```json
|
||||
[
|
||||
{"NAME": "SPECTRE VARIANT 1", "CVE": "CVE-2017-5753", "VULNERABLE": false, "INFOS": "..."},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
It carries no system, CPU, or microcode context. It has no sysfs data. It
|
||||
uses uppercase field names.
|
||||
|
||||
To migrate:
|
||||
|
||||
1. Replace `--batch json-terse` with `--batch json`.
|
||||
2. The equivalent of the old `VULNERABLE` field is `vulnerabilities[].vulnerable`.
|
||||
3. The equivalent of the old `INFOS` field is `vulnerabilities[].info`.
|
||||
4. The equivalent of the old `NAME` field is `vulnerabilities[].name`.
|
||||
5. The old format is still available as `--batch json-terse` for transition
|
||||
periods.
|
||||
382
dist/doc/batch_json.schema.json
vendored
Normal file
382
dist/doc/batch_json.schema.json
vendored
Normal file
@@ -0,0 +1,382 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://github.com/speed47/spectre-meltdown-checker/dist/batch_json.schema.json",
|
||||
"title": "spectre-meltdown-checker --batch json output",
|
||||
"description": "Schema for the comprehensive JSON output produced by spectre-meltdown-checker.sh --batch json. format_version 1.",
|
||||
"type": "object",
|
||||
"required": ["meta", "system", "cpu", "cpu_microcode", "vulnerabilities"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
|
||||
"meta": {
|
||||
"description": "Run metadata and option flags.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"script_version", "format_version", "timestamp", "os", "mode",
|
||||
"run_as_root", "reduced_accuracy", "paranoid", "sysfs_only",
|
||||
"extra", "mocked"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"script_version": {
|
||||
"description": "Script version string, e.g. '25.30.0250400123'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"format_version": {
|
||||
"description": "JSON schema version. Incremented on backward-incompatible changes. Current value: 1.",
|
||||
"type": "integer",
|
||||
"const": 1
|
||||
},
|
||||
"timestamp": {
|
||||
"description": "ISO 8601 UTC timestamp of when the scan started, e.g. '2025-04-07T12:00:00Z'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"os": {
|
||||
"description": "Operating system name from uname -s, e.g. 'Linux', 'FreeBSD'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"mode": {
|
||||
"description": "Operating mode: 'live' (default), 'no-runtime' (--no-runtime), 'no-hw' (--no-hw), or 'hw-only' (--hw-only).",
|
||||
"type": "string",
|
||||
"enum": ["live", "no-runtime", "no-hw", "hw-only"]
|
||||
},
|
||||
"run_as_root": {
|
||||
"description": "Whether the script ran as root. Non-root scans skip MSR reads and may produce incomplete or inaccurate results.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"reduced_accuracy": {
|
||||
"description": "True when the kernel image, config, or System.map was missing. Some checks fall back to weaker heuristics.",
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"paranoid": {
|
||||
"description": "True when --paranoid was set: stricter criteria (e.g. requires SMT disabled, IBPB always-on).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"sysfs_only": {
|
||||
"description": "True when --sysfs-only was set: the script trusted the kernel's own sysfs report without independent detection.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"extra": {
|
||||
"description": "True when --extra was set: additional experimental checks were enabled.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mocked": {
|
||||
"description": "True when one or more CPU values were overridden for testing. Results do NOT reflect the real system.",
|
||||
"type": ["boolean", "null"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"system": {
|
||||
"description": "Kernel and host environment context.",
|
||||
"type": ["object", "null"],
|
||||
"required": [
|
||||
"kernel_release", "kernel_version", "kernel_arch",
|
||||
"kernel_image", "kernel_config", "kernel_version_string",
|
||||
"kernel_cmdline", "cpu_count", "smt_enabled",
|
||||
"hypervisor_host", "hypervisor_host_reason"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"kernel_release": {
|
||||
"description": "Output of uname -r (live mode only), e.g. '6.1.0-21-amd64'. Null in other modes.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"kernel_version": {
|
||||
"description": "Output of uname -v (live mode only), e.g. '#1 SMP Debian …'. Null in other modes.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"kernel_arch": {
|
||||
"description": "Output of uname -m (live mode only), e.g. 'x86_64'. Null in other modes.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"kernel_image": {
|
||||
"description": "Path to the kernel image passed via --kernel. Null in live mode.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"kernel_config": {
|
||||
"description": "Path to the kernel config passed via --config. Null if not provided.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"kernel_version_string": {
|
||||
"description": "Kernel version banner extracted from the image. Null if unavailable.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"kernel_cmdline": {
|
||||
"description": "Kernel command line from /proc/cmdline (live mode) or the image. Null if unavailable.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"cpu_count": {
|
||||
"description": "Number of logical CPUs detected (max core ID + 1). Null if undeterminable.",
|
||||
"type": ["integer", "null"],
|
||||
"minimum": 1
|
||||
},
|
||||
"smt_enabled": {
|
||||
"description": "Whether SMT (HyperThreading) is currently enabled. Null if the script could not determine the state.",
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"hypervisor_host": {
|
||||
"description": "Whether this machine is detected as a VM host (running KVM, Xen, VMware, etc.). Null if undeterminable.",
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"hypervisor_host_reason": {
|
||||
"description": "Human-readable explanation of why hypervisor_host was set. Null if hypervisor_host is false or null.",
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"cpu": {
|
||||
"description": "CPU hardware identification. Null when --no-hw is active. Contains an 'arch' discriminator ('x86' or 'arm') and a matching arch-specific sub-object with identification fields and capabilities.",
|
||||
"oneOf": [
|
||||
{ "type": "null" },
|
||||
{
|
||||
"type": "object",
|
||||
"description": "x86 CPU (Intel, AMD, Hygon).",
|
||||
"required": ["arch", "vendor", "friendly_name", "x86"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"arch": { "type": "string", "const": "x86" },
|
||||
"vendor": {
|
||||
"description": "CPU vendor string: 'GenuineIntel', 'AuthenticAMD', or 'HygonGenuine'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"friendly_name": {
|
||||
"description": "Human-readable CPU model from /proc/cpuinfo, e.g. 'Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"x86": {
|
||||
"type": "object",
|
||||
"required": ["family", "model", "stepping", "cpuid", "platform_id", "hybrid", "codename", "capabilities"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"family": {
|
||||
"description": "CPU family number.",
|
||||
"type": ["integer", "null"]
|
||||
},
|
||||
"model": {
|
||||
"description": "CPU model number.",
|
||||
"type": ["integer", "null"]
|
||||
},
|
||||
"stepping": {
|
||||
"description": "CPU stepping number.",
|
||||
"type": ["integer", "null"]
|
||||
},
|
||||
"cpuid": {
|
||||
"description": "Full CPUID leaf 1 EAX value as a hex string, e.g. '0x000906ed'.",
|
||||
"type": ["string", "null"],
|
||||
"pattern": "^0x[0-9a-f]+$"
|
||||
},
|
||||
"platform_id": {
|
||||
"description": "Intel platform ID from MSR 0x17. Null on AMD.",
|
||||
"type": ["integer", "null"]
|
||||
},
|
||||
"hybrid": {
|
||||
"description": "Whether this is a hybrid CPU (P-cores + E-cores, e.g. Alder Lake). Null if undeterminable.",
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"codename": {
|
||||
"description": "Intel CPU codename, e.g. 'Coffee Lake'. Null on AMD.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"capabilities": {
|
||||
"description": "CPU feature flags detected via CPUID and MSR reads. Each value is true (present), false (absent), or null (not applicable or could not be read).",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"spec_ctrl": { "type": ["boolean", "null"], "description": "SPEC_CTRL MSR present (Intel; enables IBRS + IBPB via WRMSR)" },
|
||||
"ibrs": { "type": ["boolean", "null"], "description": "Indirect Branch Restricted Speculation" },
|
||||
"ibpb": { "type": ["boolean", "null"], "description": "Indirect Branch Prediction Barrier" },
|
||||
"ibpb_ret": { "type": ["boolean", "null"], "description": "IBPB on return (enhanced form)" },
|
||||
"stibp": { "type": ["boolean", "null"], "description": "Single Thread Indirect Branch Predictors" },
|
||||
"ssbd": { "type": ["boolean", "null"], "description": "Speculative Store Bypass Disable" },
|
||||
"l1d_flush": { "type": ["boolean", "null"], "description": "L1D cache flush instruction" },
|
||||
"md_clear": { "type": ["boolean", "null"], "description": "VERW clears CPU buffers (MDS mitigation)" },
|
||||
"arch_capabilities": { "type": ["boolean", "null"], "description": "IA32_ARCH_CAPABILITIES MSR is present" },
|
||||
"rdcl_no": { "type": ["boolean", "null"], "description": "Not susceptible to RDCL (Meltdown-like attacks)" },
|
||||
"ibrs_all": { "type": ["boolean", "null"], "description": "Enhanced IBRS always-on mode supported" },
|
||||
"rsba": { "type": ["boolean", "null"], "description": "RSB may use return predictions from outside the RSB" },
|
||||
"l1dflush_no": { "type": ["boolean", "null"], "description": "Not susceptible to L1D flush side-channel" },
|
||||
"ssb_no": { "type": ["boolean", "null"], "description": "Not susceptible to Speculative Store Bypass" },
|
||||
"mds_no": { "type": ["boolean", "null"], "description": "Not susceptible to MDS" },
|
||||
"taa_no": { "type": ["boolean", "null"], "description": "Not susceptible to TSX Asynchronous Abort" },
|
||||
"pschange_msc_no": { "type": ["boolean", "null"], "description": "Page-size-change MSC not susceptible" },
|
||||
"tsx_ctrl_msr": { "type": ["boolean", "null"], "description": "TSX_CTRL MSR is present" },
|
||||
"tsx_ctrl_rtm_disable": { "type": ["boolean", "null"], "description": "RTM disabled via TSX_CTRL" },
|
||||
"tsx_ctrl_cpuid_clear": { "type": ["boolean", "null"], "description": "CPUID HLE/RTM bits cleared via TSX_CTRL" },
|
||||
"gds_ctrl": { "type": ["boolean", "null"], "description": "GDS_CTRL MSR present" },
|
||||
"gds_no": { "type": ["boolean", "null"], "description": "Not susceptible to Gather Data Sampling" },
|
||||
"gds_mitg_dis": { "type": ["boolean", "null"], "description": "GDS mitigation disabled" },
|
||||
"gds_mitg_lock": { "type": ["boolean", "null"], "description": "GDS mitigation locked" },
|
||||
"rfds_no": { "type": ["boolean", "null"], "description": "Not susceptible to Register File Data Sampling" },
|
||||
"rfds_clear": { "type": ["boolean", "null"], "description": "VERW clears register file stale data" },
|
||||
"its_no": { "type": ["boolean", "null"], "description": "Not susceptible to Indirect Target Selection" },
|
||||
"sbdr_ssdp_no": { "type": ["boolean", "null"], "description": "Not susceptible to SBDR/SSDP" },
|
||||
"fbsdp_no": { "type": ["boolean", "null"], "description": "Not susceptible to FBSDP" },
|
||||
"psdp_no": { "type": ["boolean", "null"], "description": "Not susceptible to PSDP" },
|
||||
"fb_clear": { "type": ["boolean", "null"], "description": "Fill buffer cleared on idle/C6" },
|
||||
"rtm": { "type": ["boolean", "null"], "description": "Restricted Transactional Memory (TSX RTM) present" },
|
||||
"tsx_force_abort": { "type": ["boolean", "null"], "description": "TSX_FORCE_ABORT MSR present" },
|
||||
"tsx_force_abort_rtm_disable": { "type": ["boolean", "null"], "description": "RTM disabled via TSX_FORCE_ABORT" },
|
||||
"tsx_force_abort_cpuid_clear": { "type": ["boolean", "null"], "description": "CPUID RTM cleared via TSX_FORCE_ABORT" },
|
||||
"sgx": { "type": ["boolean", "null"], "description": "Software Guard Extensions present" },
|
||||
"srbds": { "type": ["boolean", "null"], "description": "SRBDS affected" },
|
||||
"srbds_on": { "type": ["boolean", "null"], "description": "SRBDS mitigation active" },
|
||||
"amd_ssb_no": { "type": ["boolean", "null"], "description": "AMD: not susceptible to Speculative Store Bypass" },
|
||||
"hygon_ssb_no": { "type": ["boolean", "null"], "description": "Hygon: not susceptible to Speculative Store Bypass" },
|
||||
"ipred": { "type": ["boolean", "null"], "description": "Indirect Predictor Barrier support" },
|
||||
"rrsba": { "type": ["boolean", "null"], "description": "Restricted RSB Alternate (Intel Retbleed mitigation)" },
|
||||
"bhi": { "type": ["boolean", "null"], "description": "Branch History Injection mitigation support" },
|
||||
"tsa_sq_no": { "type": ["boolean", "null"], "description": "Not susceptible to TSA-SQ" },
|
||||
"tsa_l1_no": { "type": ["boolean", "null"], "description": "Not susceptible to TSA-L1" },
|
||||
"verw_clear": { "type": ["boolean", "null"], "description": "VERW clears CPU buffers" },
|
||||
"autoibrs": { "type": ["boolean", "null"], "description": "AMD AutoIBRS (equivalent to enhanced IBRS on Intel)" },
|
||||
"sbpb": { "type": ["boolean", "null"], "description": "Selective Branch Predictor Barrier (AMD Inception mitigation)" },
|
||||
"avx2": { "type": ["boolean", "null"], "description": "AVX2 supported (relevant to Downfall / GDS)" },
|
||||
"avx512": { "type": ["boolean", "null"], "description": "AVX-512 supported (relevant to Downfall / GDS)" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "ARM CPU (ARM, Cavium, Phytium).",
|
||||
"required": ["arch", "vendor", "friendly_name", "arm"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"arch": { "type": "string", "const": "arm" },
|
||||
"vendor": {
|
||||
"description": "CPU vendor string: 'ARM', 'CAVIUM', or 'PHYTIUM'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"friendly_name": {
|
||||
"description": "Human-readable CPU model, e.g. 'ARM v8 model 0xd0b'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"arm": {
|
||||
"type": "object",
|
||||
"required": ["part_list", "arch_list", "capabilities"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"part_list": {
|
||||
"description": "Space-separated list of ARM part numbers detected across cores, e.g. '0xd0b 0xd05' (big.LITTLE).",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"arch_list": {
|
||||
"description": "Space-separated list of ARM architecture levels detected across cores, e.g. '8 8'.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"capabilities": {
|
||||
"description": "ARM-specific CPU capability flags. Currently empty; reserved for future use.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"cpu_microcode": {
|
||||
"description": "Microcode version and firmware database status. Null under the same conditions as cpu.",
|
||||
"type": ["object", "null"],
|
||||
"required": [
|
||||
"installed_version", "latest_version", "microcode_up_to_date",
|
||||
"is_blacklisted", "message", "db_source", "db_info"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"installed_version": {
|
||||
"description": "Currently running microcode revision as a hex string, e.g. '0xf4'. Null if unreadable.",
|
||||
"type": ["string", "null"],
|
||||
"pattern": "^0x[0-9a-f]+$"
|
||||
},
|
||||
"latest_version": {
|
||||
"description": "Latest known-good microcode version from the firmware database, as a hex string. Null if the CPU is not in the database.",
|
||||
"type": ["string", "null"],
|
||||
"pattern": "^0x[0-9a-f]+$"
|
||||
},
|
||||
"microcode_up_to_date": {
|
||||
"description": "True when installed_version equals latest_version. Null if either is unavailable.",
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"is_blacklisted": {
|
||||
"description": "True when the installed microcode is known to cause instability and must be rolled back immediately.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"description": "Human-readable note from the firmware database (e.g. changelog excerpt). Null if absent.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"db_source": {
|
||||
"description": "Which firmware database was used, e.g. 'Intel-SA', 'MCExtractor'. Null if unavailable.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"db_info": {
|
||||
"description": "Firmware database revision or date string. Null if unavailable.",
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"vulnerabilities": {
|
||||
"description": "Array of CVE check results, one per checked CVE, in check order.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"cve", "name", "aliases", "cpu_affected",
|
||||
"status", "vulnerable", "info",
|
||||
"sysfs_status", "sysfs_message"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"cve": {
|
||||
"description": "CVE identifier, e.g. 'CVE-2017-5753'. May be 'CVE-0000-0001' for non-CVE checks such as SLS.",
|
||||
"type": "string",
|
||||
"pattern": "^CVE-[0-9]{4}-[0-9]+$"
|
||||
},
|
||||
"name": {
|
||||
"description": "Short key name used across batch formats, e.g. 'SPECTRE VARIANT 1'.",
|
||||
"type": "string"
|
||||
},
|
||||
"aliases": {
|
||||
"description": "Full name including all known aliases, e.g. 'Spectre Variant 1, bounds check bypass'. Null if not in the registry.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"cpu_affected": {
|
||||
"description": "Whether this CPU's hardware design is affected by this CVE. False when hardware is architecturally immune.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"description": "Check outcome: 'OK'=not vulnerable or unaffected, 'VULN'=vulnerable, 'UNK'=could not determine.",
|
||||
"type": "string",
|
||||
"enum": ["OK", "VULN", "UNK"]
|
||||
},
|
||||
"vulnerable": {
|
||||
"description": "Boolean encoding of status: false=OK, true=VULN, null=UNK.",
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"info": {
|
||||
"description": "Human-readable description of the specific mitigation state or reason for the verdict.",
|
||||
"type": "string"
|
||||
},
|
||||
"sysfs_status": {
|
||||
"description": "Status as reported by the kernel via /sys/devices/system/cpu/vulnerabilities/. Null if sysfs was not consulted for this CVE (older kernels, or CVE not tracked by the kernel).",
|
||||
"type": ["string", "null"],
|
||||
"enum": ["OK", "VULN", "UNK", null]
|
||||
},
|
||||
"sysfs_message": {
|
||||
"description": "Raw text from the sysfs vulnerability file, e.g. 'Mitigation: PTI'. Null if sysfs was not consulted.",
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
149
dist/doc/batch_nrpe.md
vendored
Normal file
149
dist/doc/batch_nrpe.md
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
# NRPE Output Format
|
||||
|
||||
`--batch nrpe` produces output that conforms to the
|
||||
[Nagios Plugin Development Guidelines](https://nagios-plugins.org/doc/guidelines.html),
|
||||
making it directly consumable by Nagios, Icinga, Zabbix (via NRPE), and
|
||||
compatible monitoring stacks.
|
||||
|
||||
```sh
|
||||
sudo ./spectre-meltdown-checker.sh --batch nrpe
|
||||
```
|
||||
|
||||
## Output structure
|
||||
|
||||
The plugin emits one mandatory status line followed by optional long output:
|
||||
|
||||
```
|
||||
STATUS: summary | checked=N vulnerable=N unknown=N
|
||||
NOTE: ... ← context notes (when applicable)
|
||||
[CRITICAL] CVE-XXXX-YYYY (NAME): description
|
||||
[UNKNOWN] CVE-XXXX-YYYY (NAME): description
|
||||
```
|
||||
|
||||
### Line 1 (status line)
|
||||
|
||||
Always present. Parsed by every Nagios-compatible monitoring system.
|
||||
|
||||
```
|
||||
STATUS: summary | perfdata
|
||||
```
|
||||
|
||||
| Field | Values | Meaning |
|
||||
|---|---|---|
|
||||
| `STATUS` | `OK` / `CRITICAL` / `UNKNOWN` | Overall check outcome (see below) |
|
||||
| `summary` | human-readable string | Count and CVE IDs of affected checks |
|
||||
| `perfdata` | `checked=N vulnerable=N unknown=N` | Machine-readable counters for graphing |
|
||||
|
||||
#### Status values
|
||||
|
||||
| Status | Exit code | Condition |
|
||||
|---|---|---|
|
||||
| `OK` | `0` | All CVE checks passed |
|
||||
| `CRITICAL` | `2` | At least one CVE is vulnerable |
|
||||
| `UNKNOWN` | `3` | No VULN found, but at least one check is inconclusive **or** the script was not run as root and found apparent vulnerabilities (see below) |
|
||||
|
||||
#### Summary format
|
||||
|
||||
| Condition | Summary |
|
||||
|---|---|
|
||||
| All OK | `All N CVE checks passed` |
|
||||
| VULN only | `N/T CVE(s) vulnerable: CVE-A CVE-B ...` |
|
||||
| VULN + UNK | `N/T CVE(s) vulnerable: CVE-A CVE-B ..., M inconclusive` |
|
||||
| UNK only | `N/T CVE checks inconclusive` |
|
||||
| Non-root + VULN | `N/T CVE(s) appear vulnerable (unconfirmed, not root): CVE-A ...` |
|
||||
|
||||
### Lines 2+ (long output)
|
||||
|
||||
Shown in the detail/extended info view of most monitoring frontends.
|
||||
Never parsed by the monitoring core; safe to add or reorder.
|
||||
|
||||
#### Context notes
|
||||
|
||||
Printed before per-CVE details when applicable:
|
||||
|
||||
| Note | Condition |
|
||||
|---|---|
|
||||
| `NOTE: paranoid mode active, stricter mitigation requirements applied` | `--paranoid` was used |
|
||||
| `NOTE: hypervisor host detected (reason); L1TF/MDS severity is elevated` | System is a VM host (KVM, Xen, VMware…) |
|
||||
| `NOTE: not a hypervisor host` | System is confirmed not a VM host |
|
||||
| `NOTE: not running as root; MSR reads skipped, results may be incomplete` | Script ran without root privileges |
|
||||
|
||||
#### Per-CVE detail lines
|
||||
|
||||
One line per non-OK CVE. VULN entries (`[CRITICAL]`) appear before UNK
|
||||
entries (`[UNKNOWN]`); within each group the order follows the CVE registry.
|
||||
|
||||
```
|
||||
[CRITICAL] CVE-XXXX-YYYY (SHORT NAME): mitigation status description
|
||||
[UNKNOWN] CVE-XXXX-YYYY (SHORT NAME): reason check was inconclusive
|
||||
```
|
||||
|
||||
## Exit codes
|
||||
|
||||
| Code | Nagios meaning | Condition |
|
||||
|---|---|---|
|
||||
| `0` | OK | All checked CVEs are mitigated or hardware-unaffected |
|
||||
| `2` | CRITICAL | At least one CVE is vulnerable (script ran as root) |
|
||||
| `3` | UNKNOWN | At least one check inconclusive, or apparent VULN found without root |
|
||||
| `255` | - | Script error (bad arguments, unsupported platform) |
|
||||
|
||||
Exit code `1` (WARNING) is not used; there is no "degraded but acceptable"
|
||||
state for CPU vulnerability mitigations.
|
||||
|
||||
## Non-root behaviour
|
||||
|
||||
Running without root privileges skips MSR reads and limits access to some
|
||||
kernel interfaces. When the script finds apparent vulnerabilities without root:
|
||||
|
||||
- The status word becomes `UNKNOWN` instead of `CRITICAL`
|
||||
- The exit code is `3` instead of `2`
|
||||
- The summary says `appear vulnerable (unconfirmed, not root)`
|
||||
- A `NOTE: not running as root` line is added to the long output
|
||||
|
||||
**Recommendation:** always run with `sudo` for authoritative results. A
|
||||
`CRITICAL` from a root-run scan is a confirmed vulnerability; an `UNKNOWN`
|
||||
from a non-root scan is a signal to investigate further.
|
||||
|
||||
## Hypervisor hosts
|
||||
|
||||
When `NOTE: hypervisor host detected` is present, L1TF (CVE-2018-3646) and
|
||||
MDS (CVE-2018-12126/12130/12127) carry significantly higher risk because
|
||||
they can be exploited across VM boundaries by a malicious guest. Prioritise
|
||||
remediation on these hosts.
|
||||
|
||||
## Examples
|
||||
|
||||
**All mitigated (root):**
|
||||
```
|
||||
OK: All 31 CVE checks passed | checked=31 vulnerable=0 unknown=0
|
||||
NOTE: not a hypervisor host
|
||||
```
|
||||
Exit: `0`
|
||||
|
||||
**Two CVEs vulnerable (root):**
|
||||
```
|
||||
CRITICAL: 2/31 CVE(s) vulnerable: CVE-2018-3615 CVE-2019-11135 | checked=31 vulnerable=2 unknown=0
|
||||
NOTE: not a hypervisor host
|
||||
[CRITICAL] CVE-2018-3615 (L1TF SGX): your CPU supports SGX and the microcode is not up to date
|
||||
[CRITICAL] CVE-2019-11135 (TAA): Your kernel doesn't support TAA mitigation, update it
|
||||
```
|
||||
Exit: `2`
|
||||
|
||||
**Apparent vulnerabilities, non-root scan:**
|
||||
```
|
||||
UNKNOWN: 2/31 CVE(s) appear vulnerable (unconfirmed, not root): CVE-2018-3615 CVE-2019-11135 | checked=31 vulnerable=2 unknown=0
|
||||
NOTE: not a hypervisor host
|
||||
NOTE: not running as root; MSR reads skipped, results may be incomplete
|
||||
[CRITICAL] CVE-2018-3615 (L1TF SGX): your CPU supports SGX and the microcode is not up to date
|
||||
[CRITICAL] CVE-2019-11135 (TAA): Your kernel doesn't support TAA mitigation, update it
|
||||
```
|
||||
Exit: `3`
|
||||
|
||||
**Inconclusive checks, paranoid mode, VMM host:**
|
||||
```
|
||||
UNKNOWN: 3/31 CVE checks inconclusive | checked=31 vulnerable=0 unknown=3
|
||||
NOTE: paranoid mode active, stricter mitigation requirements applied
|
||||
NOTE: hypervisor host detected (kvm); L1TF/MDS severity is elevated
|
||||
[UNKNOWN] CVE-2018-3646 (L1TF VMM): SMT is enabled on a hypervisor host, not mitigated under paranoid mode
|
||||
```
|
||||
Exit: `3`
|
||||
377
dist/doc/batch_prometheus.md
vendored
Normal file
377
dist/doc/batch_prometheus.md
vendored
Normal file
@@ -0,0 +1,377 @@
|
||||
# Prometheus Batch Mode
|
||||
|
||||
`--batch prometheus` emits Prometheus text-format metrics that can be fed into any
|
||||
Prometheus-compatible monitoring stack. It is designed for **fleet-scale security
|
||||
monitoring**: run the script periodically on every host, push the output to a
|
||||
Prometheus Pushgateway (or drop it into a node_exporter textfile directory), then
|
||||
alert and dashboard from Prometheus/Grafana like any other infrastructure metric.
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
### Pushgateway (recommended for cron/batch fleet scans)
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
PUSHGATEWAY="http://pushgateway.internal:9091"
|
||||
INSTANCE=$(hostname -f)
|
||||
|
||||
spectre-meltdown-checker.sh --batch prometheus \
|
||||
| curl --silent --show-error --data-binary @- \
|
||||
"${PUSHGATEWAY}/metrics/job/smc/instance/${INSTANCE}"
|
||||
```
|
||||
|
||||
Run this as root via cron or a systemd timer on every host. The Pushgateway
|
||||
retains the last pushed value, so Prometheus scrapes it on its own schedule.
|
||||
A stale-data alert (`smc_last_scan_timestamp_seconds`) catches hosts that stopped
|
||||
reporting.
|
||||
|
||||
### node_exporter textfile collector
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
TEXTFILE_DIR="/var/lib/node_exporter/textfile_collector"
|
||||
TMP="${TEXTFILE_DIR}/smc.prom.$$"
|
||||
|
||||
spectre-meltdown-checker.sh --batch prometheus > "$TMP"
|
||||
mv "$TMP" "${TEXTFILE_DIR}/smc.prom"
|
||||
```
|
||||
|
||||
The atomic `mv` prevents node_exporter from reading a partially written file.
|
||||
node_exporter must be started with `--collector.textfile.directory` pointing at
|
||||
`TEXTFILE_DIR`.
|
||||
|
||||
---
|
||||
|
||||
## Metric reference
|
||||
|
||||
All metric names are prefixed `smc_` (spectre-meltdown-checker). All metrics
|
||||
are **gauges**: they represent the state at the time of the scan, not a running
|
||||
counter.
|
||||
|
||||
---
|
||||
|
||||
### `smc_build_info`
|
||||
|
||||
Script metadata. Always value `1`; all data is in labels.
|
||||
|
||||
| Label | Values | Meaning |
|
||||
|---|---|---|
|
||||
| `version` | string | Script version (e.g. `25.30.0250400123`) |
|
||||
| `mode` | `live` / `offline` | `live` = running on the active kernel; `offline` = inspecting a kernel image |
|
||||
| `run_as_root` | `true` / `false` | Whether the script ran as root. Non-root scans skip MSR reads and may miss mitigations |
|
||||
| `paranoid` | `true` / `false` | `--paranoid` mode: stricter criteria (e.g. requires SMT disabled) |
|
||||
| `sysfs_only` | `true` / `false` | `--sysfs-only` mode: only the kernel's own sysfs report was used, not independent detection |
|
||||
| `reduced_accuracy` | `true` / `false` | Kernel information was incomplete (no kernel image, config, or map); some checks may be less precise |
|
||||
| `mocked` | `true` / `false` | Debug/test mode: CPU values were overridden. Results do **not** reflect the real system |
|
||||
|
||||
**Example:**
|
||||
```
|
||||
smc_build_info{version="25.30.0250400123",mode="live",run_as_root="true",paranoid="false",sysfs_only="false",reduced_accuracy="false",mocked="false"} 1
|
||||
```
|
||||
|
||||
**Important labels for fleet operators:**
|
||||
|
||||
- `run_as_root="false"` means the scan was incomplete. Treat those results as
|
||||
lower confidence and alert separately.
|
||||
- `sysfs_only="true"` means the script trusted the kernel's self-report without
|
||||
independent verification. The kernel may be wrong about its own mitigation
|
||||
status (known to happen on older kernels).
|
||||
- `paranoid="true"` raises the bar: a host with `paranoid="true"` and
|
||||
`vulnerable_count=0` is held to a higher standard than one with `paranoid="false"`.
|
||||
Do not compare counts across hosts with different `paranoid` values.
|
||||
- `mocked="true"` must never appear on a production host; if it does, the results
|
||||
are fabricated and every downstream alert is unreliable.
|
||||
|
||||
---
|
||||
|
||||
### `smc_system_info`
|
||||
|
||||
Operating system and kernel metadata. Always value `1`.
|
||||
|
||||
Absent in offline mode when neither `uname -r` nor `uname -m` is available.
|
||||
|
||||
| Label | Values | Meaning |
|
||||
|---|---|---|
|
||||
| `kernel_release` | string | Output of `uname -r` (live mode only) |
|
||||
| `kernel_arch` | string | Output of `uname -m` (live mode only) |
|
||||
| `hypervisor_host` | `true` / `false` | Whether this machine is detected as a hypervisor host (running KVM, Xen, VMware, etc.) |
|
||||
|
||||
**Example:**
|
||||
```
|
||||
smc_system_info{kernel_release="5.15.0-100-generic",kernel_arch="x86_64",hypervisor_host="false"} 1
|
||||
```
|
||||
|
||||
**`hypervisor_host`** materially changes the risk profile of several CVEs.
|
||||
L1TF (CVE-2018-3646) and MDS (CVE-2018-12126/12130/12127) are significantly more
|
||||
severe on hypervisor hosts because they can be exploited across VM boundaries by
|
||||
a malicious guest. Always prioritise remediation on hosts where
|
||||
`hypervisor_host="true"`.
|
||||
|
||||
---
|
||||
|
||||
### `smc_cpu_info`
|
||||
|
||||
CPU hardware and microcode metadata. Always value `1`. Absent when `--no-hw`
|
||||
is used.
|
||||
|
||||
| Label | Values | Meaning |
|
||||
|---|---|---|
|
||||
| `vendor` | string | CPU vendor (e.g. `Intel`, `AuthenticAMD`) |
|
||||
| `model` | string | CPU friendly name from `/proc/cpuinfo` |
|
||||
| `family` | integer string | CPU family number |
|
||||
| `model_id` | integer string | CPU model number |
|
||||
| `stepping` | integer string | CPU stepping number |
|
||||
| `cpuid` | hex string | Full CPUID value (e.g. `0x000906ed`); absent on some ARM CPUs |
|
||||
| `codename` | string | Intel CPU codename (e.g. `Coffee Lake`); absent on AMD and ARM |
|
||||
| `smt` | `true` / `false` | Whether SMT (HyperThreading) is currently enabled |
|
||||
| `microcode` | hex string | Installed microcode version (e.g. `0xf4`) |
|
||||
| `microcode_latest` | hex string | Latest known-good microcode version from the firmware database |
|
||||
| `microcode_up_to_date` | `true` / `false` | Whether `microcode == microcode_latest` |
|
||||
| `microcode_blacklisted` | `true` / `false` | Whether the installed microcode is known to cause problems and should be rolled back |
|
||||
|
||||
**Example:**
|
||||
```
|
||||
smc_cpu_info{vendor="Intel",model="Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",family="6",model_id="158",stepping="13",cpuid="0x000906ed",codename="Coffee Lake",smt="true",microcode="0xf4",microcode_latest="0xf4",microcode_up_to_date="true",microcode_blacklisted="false"} 1
|
||||
```
|
||||
|
||||
**Microcode labels:**
|
||||
|
||||
- `microcode_up_to_date="false"` means a newer microcode is available in the
|
||||
firmware database. This does not necessarily mean the system is vulnerable
|
||||
(the current microcode may still provide all required mitigations), but it
|
||||
warrants investigation.
|
||||
- `microcode_blacklisted="true"` means the installed microcode is known to
|
||||
cause system instability or incorrect behaviour and must be rolled back
|
||||
immediately. Treat this as a P1 incident.
|
||||
- `microcode_latest` may be absent if the CPU is not in the firmware database
|
||||
(very new, very old, or exotic CPUs).
|
||||
|
||||
**`smt`** affects the risk level of several CVEs (MDS, L1TF). For those CVEs,
|
||||
full mitigation requires disabling SMT in addition to kernel and microcode updates.
|
||||
The script accounts for this in its status assessment; use this label to audit
|
||||
which hosts still have SMT enabled.
|
||||
|
||||
---
|
||||
|
||||
### `smc_vulnerability_status`
|
||||
|
||||
One time series per CVE. The **numeric value** encodes the check result:
|
||||
|
||||
| Value | Meaning |
|
||||
|---|---|
|
||||
| `0` | Not vulnerable (CPU is unaffected by design, or all required mitigations are in place) |
|
||||
| `1` | Vulnerable (mitigations are missing or insufficient) |
|
||||
| `2` | Unknown (the script could not determine the status, e.g. due to missing kernel info or insufficient privileges) |
|
||||
|
||||
| Label | Values | Meaning |
|
||||
|---|---|---|
|
||||
| `cve` | CVE ID string | The CVE identifier (e.g. `CVE-2017-5753`) |
|
||||
| `name` | string | Human-readable CVE name and aliases (e.g. `Spectre Variant 1, bounds check bypass`) |
|
||||
| `cpu_affected` | `true` / `false` | Whether this CPU's hardware design is concerned by this CVE |
|
||||
|
||||
**Example:**
|
||||
```
|
||||
smc_vulnerability_status{cve="CVE-2017-5753",name="Spectre Variant 1, bounds check bypass",cpu_affected="true"} 0
|
||||
smc_vulnerability_status{cve="CVE-2017-5715",name="Spectre Variant 2, branch target injection",cpu_affected="true"} 1
|
||||
smc_vulnerability_status{cve="CVE-2022-29900",name="Retbleed, arbitrary speculative code execution with return instructions (AMD)",cpu_affected="false"} 0
|
||||
```
|
||||
|
||||
**`cpu_affected` explained:**
|
||||
|
||||
A value of `0` with `cpu_affected="false"` means the CPU hardware is architecturally
|
||||
immune to this CVE, no patch was needed or applied.
|
||||
|
||||
A value of `0` with `cpu_affected="true"` means the CPU has the hardware weakness
|
||||
but all required mitigations (kernel, microcode, or both) are in place.
|
||||
|
||||
This distinction is important when auditing a fleet: if you need to verify that
|
||||
all at-risk systems are patched, filter on `cpu_affected="true"` to exclude
|
||||
hardware-immune systems from the analysis.
|
||||
|
||||
---
|
||||
|
||||
### `smc_vulnerable_count`
|
||||
|
||||
Number of CVEs with status `1` (vulnerable) in this scan. Value is `0` when
|
||||
no CVEs are vulnerable.
|
||||
|
||||
---
|
||||
|
||||
### `smc_unknown_count`
|
||||
|
||||
Number of CVEs with status `2` (unknown) in this scan. A non-zero value
|
||||
typically means the scan lacked sufficient privileges or kernel information.
|
||||
Treat unknown the same as vulnerable for alerting purposes.
|
||||
|
||||
---
|
||||
|
||||
### `smc_last_scan_timestamp_seconds`
|
||||
|
||||
Unix timestamp (seconds since epoch) when the scan completed. Use this to
|
||||
detect hosts that have stopped reporting.
|
||||
|
||||
---
|
||||
|
||||
## Alerting rules
|
||||
|
||||
```yaml
|
||||
groups:
|
||||
- name: spectre_meltdown_checker
|
||||
rules:
|
||||
|
||||
# Fire when any CVE is confirmed vulnerable
|
||||
- alert: SMCVulnerable
|
||||
expr: smc_vulnerable_count > 0
|
||||
for: 0m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "{{ $labels.instance }} has {{ $value }} vulnerable CVE(s)"
|
||||
description: >
|
||||
Run spectre-meltdown-checker.sh interactively on {{ $labels.instance }}
|
||||
for remediation guidance.
|
||||
|
||||
# Fire when status is unknown (usually means scan ran without root)
|
||||
- alert: SMCUnknown
|
||||
expr: smc_unknown_count > 0
|
||||
for: 0m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "{{ $labels.instance }} has {{ $value }} CVE(s) with unknown status"
|
||||
description: >
|
||||
Ensure the checker runs as root on {{ $labels.instance }}.
|
||||
|
||||
# Fire when a host stops reporting (scan not run in 8 days)
|
||||
- alert: SMCScanStale
|
||||
expr: time() - smc_last_scan_timestamp_seconds > 8 * 86400
|
||||
for: 0m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "{{ $labels.instance }} has not reported scan results in 8 days"
|
||||
|
||||
# Fire when installed microcode is known-bad
|
||||
- alert: SMCMicrocodeBlacklisted
|
||||
expr: smc_cpu_info{microcode_blacklisted="true"} == 1
|
||||
for: 0m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "{{ $labels.instance }} is running blacklisted microcode"
|
||||
description: >
|
||||
The installed microcode ({{ $labels.microcode }}) is known to cause
|
||||
instability. Roll back to the previous version immediately.
|
||||
|
||||
# Fire when scan ran without root (results may be incomplete)
|
||||
- alert: SMCScanNotRoot
|
||||
expr: smc_build_info{run_as_root="false"} == 1
|
||||
for: 0m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "{{ $labels.instance }} scan ran without root privileges"
|
||||
|
||||
# Fire when mocked data is detected on a production host
|
||||
- alert: SMCScanMocked
|
||||
expr: smc_build_info{mocked="true"} == 1
|
||||
for: 0m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "{{ $labels.instance }} scan results are mocked and unreliable"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Useful PromQL queries
|
||||
|
||||
```promql
|
||||
# All vulnerable CVEs across the fleet
|
||||
smc_vulnerability_status == 1
|
||||
|
||||
# Vulnerable CVEs on hosts that are also hypervisor hosts (highest priority)
|
||||
smc_vulnerability_status == 1
|
||||
* on(instance) group_left(hypervisor_host)
|
||||
smc_system_info{hypervisor_host="true"}
|
||||
|
||||
# Vulnerable CVEs on affected CPUs only (excludes hardware-immune systems)
|
||||
smc_vulnerability_status{cpu_affected="true"} == 1
|
||||
|
||||
# Fleet-wide: how many hosts are vulnerable to each CVE
|
||||
count by (cve, name) (smc_vulnerability_status == 1)
|
||||
|
||||
# Hosts with outdated microcode, with CPU model context
|
||||
smc_cpu_info{microcode_up_to_date="false"}
|
||||
|
||||
# Hosts with SMT still enabled (relevant for MDS/L1TF remediation)
|
||||
smc_cpu_info{smt="true"}
|
||||
|
||||
# For a specific CVE: hosts affected by hardware but fully mitigated
|
||||
smc_vulnerability_status{cve="CVE-2018-3646", cpu_affected="true"} == 0
|
||||
|
||||
# Proportion of fleet that is fully clean (no vulnerable, no unknown)
|
||||
(
|
||||
count(smc_vulnerable_count == 0 and smc_unknown_count == 0)
|
||||
/
|
||||
count(smc_vulnerable_count >= 0)
|
||||
)
|
||||
|
||||
# Hosts where scan ran without root, results less reliable
|
||||
smc_build_info{run_as_root="false"}
|
||||
|
||||
# Hosts with sysfs_only mode, independent detection was skipped
|
||||
smc_build_info{sysfs_only="true"}
|
||||
|
||||
# Vulnerable CVEs joined with kernel release for patch tracking
|
||||
smc_vulnerability_status == 1
|
||||
* on(instance) group_left(kernel_release)
|
||||
smc_system_info
|
||||
|
||||
# Vulnerable CVEs joined with CPU model and microcode version
|
||||
smc_vulnerability_status == 1
|
||||
* on(instance) group_left(vendor, model, microcode, microcode_up_to_date)
|
||||
smc_cpu_info
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Caveats and edge cases
|
||||
|
||||
**Offline mode (`--kernel`)**
|
||||
`smc_system_info` will have no `kernel_release` or `kernel_arch` labels (those
|
||||
come from `uname`, which reports the running kernel, not the inspected one).
|
||||
`mode="offline"` in `smc_build_info` signals this. Offline mode is primarily
|
||||
useful for pre-deployment auditing, not fleet runtime monitoring.
|
||||
|
||||
**`--no-hw`**
|
||||
`smc_cpu_info` is not emitted. CPU and microcode labels are absent from all
|
||||
queries. CVE checks that rely on hardware capability detection (`cap_*` flags,
|
||||
MSR reads) will report `unknown` status.
|
||||
|
||||
**`--sysfs-only`**
|
||||
The script trusts the kernel's sysfs report (`/sys/devices/system/cpu/vulnerabilities/`)
|
||||
without running its own independent detection. Some older kernels are known to
|
||||
misreport their mitigation status. `sysfs_only="true"` in `smc_build_info`
|
||||
flags this condition. Do not use `--sysfs-only` for production fleet monitoring.
|
||||
|
||||
**`--paranoid`**
|
||||
Enables defense-in-depth checks beyond the security community consensus (e.g.
|
||||
requires SMT to be disabled, IBPB always-on). A host is only `vulnerable_count=0`
|
||||
under `paranoid` if it meets this higher bar. Do not compare `vulnerable_count`
|
||||
across hosts with different `paranoid` values.
|
||||
|
||||
**`reduced_accuracy`**
|
||||
Set when the kernel image, config file, or System.map could not be read. Some
|
||||
checks fall back to weaker heuristics and may report `unknown` for CVEs that are
|
||||
actually mitigated. This typically happens when the script runs without root or
|
||||
on a kernel with an inaccessible image.
|
||||
|
||||
**Label stability**
|
||||
Prometheus identifies time series by their full label set. If a script upgrade
|
||||
adds or renames a label (e.g. a new `smc_cpu_info` label is added for a new CVE),
|
||||
Prometheus will create a new time series and the old one will become stale. Plan
|
||||
for this in long-retention dashboards by using `group_left` joins rather than
|
||||
hardcoding label matchers.
|
||||
Reference in New Issue
Block a user