mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-04-27 19:13:19 +02:00
Compare commits
5 Commits
48454a5344
...
source
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e2b6cc734 | ||
|
|
e2d110a3b5 | ||
|
|
1bb33d5cf2 | ||
|
|
6732eb141b | ||
|
|
048ce5b6a2 |
36
.github/workflows/autoupdate.yml
vendored
36
.github/workflows/autoupdate.yml
vendored
@@ -1,36 +0,0 @@
|
|||||||
name: autoupdate
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: '42 9 * * *'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
autoupdate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install prerequisites
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends iucode-tool sqlite3 unzip
|
|
||||||
- name: Update microcode versions
|
|
||||||
run: ./spectre-meltdown-checker.sh --update-builtin-fwdb
|
|
||||||
- name: Check git diff
|
|
||||||
id: diff
|
|
||||||
run: |
|
|
||||||
echo change="$(git diff spectre-meltdown-checker.sh | awk '/MCEDB/ { if(V) { print V" to "$4; exit } else { V=$4 } }')" >> "$GITHUB_OUTPUT"
|
|
||||||
echo nbdiff="$(git diff spectre-meltdown-checker.sh | grep -cE -- '^\+# [AI],')" >> "$GITHUB_OUTPUT"
|
|
||||||
git diff
|
|
||||||
cat "$GITHUB_OUTPUT"
|
|
||||||
- name: Create Pull Request if needed
|
|
||||||
if: steps.diff.outputs.nbdiff != '0'
|
|
||||||
uses: peter-evans/create-pull-request@v7
|
|
||||||
with:
|
|
||||||
branch: autoupdate-fwdb
|
|
||||||
commit-message: "update: fwdb from ${{ steps.diff.outputs.change }}, ${{ steps.diff.outputs.nbdiff }} microcode changes"
|
|
||||||
title: "[Auto] Update fwdb from ${{ steps.diff.outputs.change }}"
|
|
||||||
body: |
|
|
||||||
Automated PR to update fwdb from ${{ steps.diff.outputs.change }}
|
|
||||||
Detected ${{ steps.diff.outputs.nbdiff }} microcode changes
|
|
||||||
2
.github/workflows/expected_cve_count
vendored
2
.github/workflows/expected_cve_count
vendored
@@ -1 +1 @@
|
|||||||
31
|
32
|
||||||
|
|||||||
33
.github/workflows/stale.yml
vendored
33
.github/workflows/stale.yml
vendored
@@ -1,33 +0,0 @@
|
|||||||
name: 'Manage stale issues and PRs'
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '37 7 * * *'
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
action:
|
|
||||||
description: "dry-run"
|
|
||||||
required: true
|
|
||||||
default: "dryrun"
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- dryrun
|
|
||||||
- apply
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v10
|
|
||||||
with:
|
|
||||||
any-of-labels: 'needs-more-info,answered'
|
|
||||||
labels-to-remove-when-unstale: 'needs-more-info,answered'
|
|
||||||
days-before-stale: 30
|
|
||||||
days-before-close: 7
|
|
||||||
stale-issue-label: stale
|
|
||||||
remove-stale-when-updated: true
|
|
||||||
debug-only: ${{ case(inputs.action == 'dryrun', true, false) }}
|
|
||||||
@@ -291,7 +291,12 @@ Before writing code, verify the CVE meets the inclusion criteria (see "CVE Inclu
|
|||||||
|
|
||||||
### Step 1: Create the Vulnerability File
|
### Step 1: Create the Vulnerability File
|
||||||
|
|
||||||
Create `src/vulns/CVE-YYYY-NNNNN.sh`. The file header must follow this exact format:
|
Create `src/vulns/CVE-YYYY-NNNNN.sh`. When no real CVE applies, two placeholder ranges are reserved:
|
||||||
|
|
||||||
|
- **`CVE-0000-NNNN`** — permanent placeholder for supplementary `--extra`-only checks that will never receive a real CVE (e.g. SLS / compile-time hardening).
|
||||||
|
- **`CVE-9999-NNNN`** — temporary placeholder for real vulnerabilities awaiting CVE assignment. Once the real CVE is issued, rename the file, the registry entry, the `--variant` alias, and the function symbols across the codebase.
|
||||||
|
|
||||||
|
The file header must follow this exact format:
|
||||||
|
|
||||||
- **Line 1**: vim modeline (`# vim: set ts=4 sw=4 sts=4 et:`)
|
- **Line 1**: vim modeline (`# vim: set ts=4 sw=4 sts=4 et:`)
|
||||||
- **Line 2**: 31 `#` characters (`###############################`)
|
- **Line 2**: 31 `#` characters (`###############################`)
|
||||||
|
|||||||
6
dist/README.md
vendored
6
dist/README.md
vendored
@@ -38,6 +38,7 @@ CVE | Name | Aliases
|
|||||||
[CVE-2024-36357](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36357) | Transient Scheduler Attack, L1 | TSA-L1
|
[CVE-2024-36357](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36357) | Transient Scheduler Attack, L1 | TSA-L1
|
||||||
[CVE-2025-40300](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-40300) | VM-Exit Stale Branch Prediction | VMScape
|
[CVE-2025-40300](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-40300) | VM-Exit Stale Branch Prediction | VMScape
|
||||||
[CVE-2024-45332](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-45332) | Branch Privilege Injection | BPI
|
[CVE-2024-45332](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-45332) | Branch Privilege Injection | BPI
|
||||||
|
[CVE-2025-54505](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54505) | AMD Zen1 Floating-Point Divider Stale Data Leak | FPDSS
|
||||||
|
|
||||||
## Am I at risk?
|
## Am I at risk?
|
||||||
|
|
||||||
@@ -77,6 +78,7 @@ CVE-2024-36350 (TSA-SQ) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel
|
|||||||
CVE-2024-36357 (TSA-L1) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
CVE-2024-36357 (TSA-L1) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||||
CVE-2025-40300 (VMScape) | ✅ | ✅ | 💥 | ✅ | Kernel update (IBPB on VM-exit)
|
CVE-2025-40300 (VMScape) | ✅ | ✅ | 💥 | ✅ | Kernel update (IBPB on VM-exit)
|
||||||
CVE-2024-45332 (BPI) | 💥 | ✅ | 💥 | ✅ | Microcode update
|
CVE-2024-45332 (BPI) | 💥 | ✅ | 💥 | ✅ | Microcode update
|
||||||
|
CVE-2025-54505 (FPDSS) | 💥 | 💥 | 💥 | 💥 | Kernel update
|
||||||
|
|
||||||
> 💥 Data can be leaked across this boundary.
|
> 💥 Data can be leaked across this boundary.
|
||||||
|
|
||||||
@@ -207,6 +209,10 @@ After a guest VM exits to the host, stale branch predictions from the guest can
|
|||||||
|
|
||||||
A race condition in the branch predictor update mechanism of Intel processors (Coffee Lake through Raptor Lake, plus some server and Atom parts) allows user-space branch predictions to briefly influence kernel-space speculative execution, undermining eIBRS and IBPB protections. This means systems relying solely on eIBRS for Spectre V2 mitigation may not be fully protected without the microcode fix. Mitigation requires a microcode update (intel-microcode 20250512+) that fixes the asynchronous branch predictor update timing so that eIBRS and IBPB work as originally intended. No kernel changes are required. Performance impact is negligible.
|
A race condition in the branch predictor update mechanism of Intel processors (Coffee Lake through Raptor Lake, plus some server and Atom parts) allows user-space branch predictions to briefly influence kernel-space speculative execution, undermining eIBRS and IBPB protections. This means systems relying solely on eIBRS for Spectre V2 mitigation may not be fully protected without the microcode fix. Mitigation requires a microcode update (intel-microcode 20250512+) that fixes the asynchronous branch predictor update timing so that eIBRS and IBPB work as originally intended. No kernel changes are required. Performance impact is negligible.
|
||||||
|
|
||||||
|
**CVE-2025-54505 — AMD Zen1 Floating-Point Divider Stale Data Leak (FPDSS)**
|
||||||
|
|
||||||
|
On AMD Zen1 and Zen+ processors (EPYC 7001, EPYC Embedded 3000, Athlon 3000 with Radeon, Ryzen 3000 with Radeon, Ryzen PRO 3000 with Radeon Vega), the hardware floating-point divider can retain partial quotient data from previous operations. Under certain circumstances, those results can be leaked to another thread sharing the same divider, crossing any privilege boundary. This was assigned CVE-2025-54505 and published by AMD as AMD-SB-7053 on 2026-04-17. Mitigation requires a kernel update (mainline commit e55d98e77561, "x86/CPU: Fix FPDSS on Zen1", Linux 7.1) that sets bit 9 (ZEN1_DENORM_FIX_BIT) of MSR 0xc0011028 (MSR_AMD64_FP_CFG) unconditionally on every Zen1 CPU at boot, disabling the hardware optimization responsible for the leak. No microcode update is required: the chicken bit is present in Zen1 silicon from the factory and is independent of microcode revision. Performance impact is limited to a small reduction in floating-point divide throughput, which is why AMD does not enable the bit by default in hardware.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Unsupported CVEs
|
## Unsupported CVEs
|
||||||
|
|||||||
11
dist/doc/UNSUPPORTED_CVE_LIST.md
vendored
11
dist/doc/UNSUPPORTED_CVE_LIST.md
vendored
@@ -124,6 +124,17 @@ A branch predictor initialization issue specific to Intel's Lion Cove microarchi
|
|||||||
|
|
||||||
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.
|
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-3665 — Lazy FP State Restore (LazyFP)
|
||||||
|
|
||||||
|
- **Advisory:** [INTEL-SA-00145](https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/lazy-fp-state-restore.html)
|
||||||
|
- **Research paper:** [LazyFP: Leaking FPU Register State using Microarchitectural Side-Channels (Stecklina & Prescher, 2018)](https://arxiv.org/abs/1806.07480)
|
||||||
|
- **Affected CPUs:** Intel Core family (Sandy Bridge through Kaby Lake) when lazy FPU switching is in use
|
||||||
|
- **CVSS:** 4.3 (Medium)
|
||||||
|
|
||||||
|
Intel CPUs using lazy FPU state switching may speculatively expose another process's FPU/SSE/AVX register contents (including AES round keys and other cryptographic material) across context switches. The `#NM` (device-not-available) exception normally used to trigger lazy restore is delivered late enough that dependent instructions can transiently execute against the stale FPU state before the fault squashes them.
|
||||||
|
|
||||||
|
**Why out of scope:** The Linux mitigation is to use eager FPU save/restore, which was already the default on Intel CPUs with XSAVEOPT well before disclosure, and was then hard-enforced upstream by the removal of all lazy FPU code in Linux 4.14 (Andy Lutomirski's "x86/fpu: Hard-disable lazy FPU mode" cleanup). There is no `/sys/devices/system/cpu/vulnerabilities/` entry, no CPUID flag, no MSR, and no kernel config option that reflects this mitigation — detection on a running kernel would require hardcoding kernel version ranges, which is against this tool's design principles (same rationale as CVE-2019-15902). In practice, any supported kernel today is eager-FPU-only, and CPUs advertising XSAVEOPT/XSAVES cannot enter the vulnerable lazy-switching mode regardless of kernel configuration.
|
||||||
|
|
||||||
## CVE-2018-9056 — BranchScope
|
## CVE-2018-9056 — BranchScope
|
||||||
|
|
||||||
- **Issue:** [#169](https://github.com/speed47/spectre-meltdown-checker/issues/169)
|
- **Issue:** [#169](https://github.com/speed47/spectre-meltdown-checker/issues/169)
|
||||||
|
|||||||
8
dist/doc/batch_json.md
vendored
8
dist/doc/batch_json.md
vendored
@@ -102,7 +102,9 @@ boundaries by a malicious guest. Prioritise remediation where
|
|||||||
|
|
||||||
### `cpu`
|
### `cpu`
|
||||||
|
|
||||||
CPU hardware identification. `null` when `--no-hw` is active.
|
CPU hardware identification. `null` when `--no-hw` is active, or when
|
||||||
|
`--arch-prefix` is set (host CPU info is then suppressed to avoid mixing
|
||||||
|
with a different-arch target kernel).
|
||||||
|
|
||||||
The object uses `arch` as a discriminator: `"x86"` for Intel/AMD/Hygon CPUs,
|
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
|
`"arm"` for ARM/Cavium/Phytium. Arch-specific fields live under a matching
|
||||||
@@ -140,7 +142,7 @@ fields from the other architecture.
|
|||||||
|
|
||||||
#### `cpu.x86.capabilities`
|
#### `cpu.x86.capabilities`
|
||||||
|
|
||||||
Each capability is a **tri-state**: `true` (present), `false` (absent), or
|
Every 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
|
`null` (not applicable or could not be read, e.g. when not root or on AMD for
|
||||||
Intel-specific features).
|
Intel-specific features).
|
||||||
|
|
||||||
@@ -238,7 +240,7 @@ with an unknown CVE ID).
|
|||||||
| `status` | string | `"OK"` / `"VULN"` / `"UNK"` | Check outcome (see below) |
|
| `status` | string | `"OK"` / `"VULN"` / `"UNK"` | Check outcome (see below) |
|
||||||
| `vulnerable` | boolean \| null | `false` / `true` / `null` | `false`=OK, `true`=VULN, `null`=UNK |
|
| `vulnerable` | boolean \| null | `false` / `true` / `null` | `false`=OK, `true`=VULN, `null`=UNK |
|
||||||
| `info` | string | | Human-readable description of the specific mitigation state or reason |
|
| `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_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, or if the CVE's check read sysfs in silent/quiet mode (raw message is still captured in `sysfs_message`) |
|
||||||
| `sysfs_message` | string \| null | | Raw text from the sysfs file (e.g. `"Mitigation: PTI"`); null if sysfs was not consulted |
|
| `sysfs_message` | string \| null | | Raw text from the sysfs file (e.g. `"Mitigation: PTI"`); null if sysfs was not consulted |
|
||||||
|
|
||||||
#### Status values
|
#### Status values
|
||||||
|
|||||||
14
dist/doc/batch_json.schema.json
vendored
14
dist/doc/batch_json.schema.json
vendored
@@ -127,7 +127,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"cpu": {
|
"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.",
|
"description": "CPU hardware identification. Null when --no-hw is active or when --arch-prefix is set (host CPU info is then suppressed to avoid mixing with a different-arch target kernel). Contains an 'arch' discriminator ('x86' or 'arm') and a matching arch-specific sub-object with identification fields and capabilities.",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{ "type": "null" },
|
{ "type": "null" },
|
||||||
{
|
{
|
||||||
@@ -180,16 +180,16 @@
|
|||||||
"type": ["string", "null"]
|
"type": ["string", "null"]
|
||||||
},
|
},
|
||||||
"capabilities": {
|
"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).",
|
"description": "CPU feature flags detected via CPUID and MSR reads. Every value is tri-state: true=present, false=absent, null=not applicable or unreadable.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"spec_ctrl": { "type": ["boolean", "null"], "description": "SPEC_CTRL MSR present (Intel; enables IBRS + IBPB via WRMSR)" },
|
"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" },
|
"ibrs": { "type": ["boolean", "null"], "description": "IBRS supported (via SPEC_CTRL, IBRS_SUPPORT, or cpuinfo fallback)" },
|
||||||
"ibpb": { "type": ["boolean", "null"], "description": "Indirect Branch Prediction Barrier" },
|
"ibpb": { "type": ["boolean", "null"], "description": "IBPB supported (via SPEC_CTRL, IBPB_SUPPORT, or cpuinfo fallback)" },
|
||||||
"ibpb_ret": { "type": ["boolean", "null"], "description": "IBPB on return (enhanced form)" },
|
"ibpb_ret": { "type": ["boolean", "null"], "description": "IBPB on return (enhanced form)" },
|
||||||
"stibp": { "type": ["boolean", "null"], "description": "Single Thread Indirect Branch Predictors" },
|
"stibp": { "type": ["boolean", "null"], "description": "STIBP supported (Intel/AMD/HYGON or cpuinfo fallback)" },
|
||||||
"ssbd": { "type": ["boolean", "null"], "description": "Speculative Store Bypass Disable" },
|
"ssbd": { "type": ["boolean", "null"], "description": "SSBD supported (SPEC_CTRL, VIRT_SPEC_CTRL, non-architectural MSR, or cpuinfo fallback)" },
|
||||||
"l1d_flush": { "type": ["boolean", "null"], "description": "L1D cache flush instruction" },
|
"l1d_flush": { "type": ["boolean", "null"], "description": "L1D cache flush instruction" },
|
||||||
"md_clear": { "type": ["boolean", "null"], "description": "VERW clears CPU buffers (MDS mitigation)" },
|
"md_clear": { "type": ["boolean", "null"], "description": "VERW clears CPU buffers (MDS mitigation)" },
|
||||||
"arch_capabilities": { "type": ["boolean", "null"], "description": "IA32_ARCH_CAPABILITIES MSR is present" },
|
"arch_capabilities": { "type": ["boolean", "null"], "description": "IA32_ARCH_CAPABILITIES MSR is present" },
|
||||||
@@ -231,7 +231,7 @@
|
|||||||
"tsa_l1_no": { "type": ["boolean", "null"], "description": "Not susceptible to TSA-L1" },
|
"tsa_l1_no": { "type": ["boolean", "null"], "description": "Not susceptible to TSA-L1" },
|
||||||
"verw_clear": { "type": ["boolean", "null"], "description": "VERW clears CPU buffers" },
|
"verw_clear": { "type": ["boolean", "null"], "description": "VERW clears CPU buffers" },
|
||||||
"autoibrs": { "type": ["boolean", "null"], "description": "AMD AutoIBRS (equivalent to enhanced IBRS on Intel)" },
|
"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)" },
|
"sbpb": { "type": ["boolean", "null"], "description": "Selective Branch Predictor Barrier (AMD Inception mitigation): true if PRED_CMD MSR SBPB bit write succeeded; false if write failed; null if not verifiable (non-root, CPUID error, or CPU does not report SBPB support)" },
|
||||||
"avx2": { "type": ["boolean", "null"], "description": "AVX2 supported (relevant to Downfall / GDS)" },
|
"avx2": { "type": ["boolean", "null"], "description": "AVX2 supported (relevant to Downfall / GDS)" },
|
||||||
"avx512": { "type": ["boolean", "null"], "description": "AVX-512 supported (relevant to Downfall / GDS)" }
|
"avx512": { "type": ["boolean", "null"], "description": "AVX-512 supported (relevant to Downfall / GDS)" }
|
||||||
}
|
}
|
||||||
|
|||||||
9
dist/doc/batch_nrpe.md
vendored
9
dist/doc/batch_nrpe.md
vendored
@@ -51,6 +51,7 @@ STATUS: summary | perfdata
|
|||||||
| VULN + UNK | `N/T CVE(s) vulnerable: CVE-A CVE-B ..., M inconclusive` |
|
| VULN + UNK | `N/T CVE(s) vulnerable: CVE-A CVE-B ..., M inconclusive` |
|
||||||
| UNK only | `N/T CVE checks inconclusive` |
|
| UNK only | `N/T CVE checks inconclusive` |
|
||||||
| Non-root + VULN | `N/T CVE(s) appear vulnerable (unconfirmed, not root): CVE-A ...` |
|
| Non-root + VULN | `N/T CVE(s) appear vulnerable (unconfirmed, not root): CVE-A ...` |
|
||||||
|
| Non-root + VULN + UNK | `N/T CVE(s) appear vulnerable (unconfirmed, not root): CVE-A ..., M inconclusive` |
|
||||||
|
|
||||||
### Lines 2+ (long output)
|
### Lines 2+ (long output)
|
||||||
|
|
||||||
@@ -59,15 +60,19 @@ Never parsed by the monitoring core; safe to add or reorder.
|
|||||||
|
|
||||||
#### Context notes
|
#### Context notes
|
||||||
|
|
||||||
Printed before per-CVE details when applicable:
|
Printed before per-CVE details when applicable. Notes are emitted in this
|
||||||
|
order when more than one applies:
|
||||||
|
|
||||||
| Note | Condition |
|
| Note | Condition |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `NOTE: paranoid mode active, stricter mitigation requirements applied` | `--paranoid` was used |
|
| `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: hypervisor host detected (reason); L1TF/MDS severity is elevated` | System is detected as a VM host (KVM, Xen, VMware…) |
|
||||||
| `NOTE: not a hypervisor host` | System is confirmed not a VM host |
|
| `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 |
|
| `NOTE: not running as root; MSR reads skipped, results may be incomplete` | Script ran without root privileges |
|
||||||
|
|
||||||
|
When VMM detection did not run (e.g. `--no-hw`), neither the
|
||||||
|
`hypervisor host detected` nor the `not a hypervisor host` note is printed.
|
||||||
|
|
||||||
#### Per-CVE detail lines
|
#### Per-CVE detail lines
|
||||||
|
|
||||||
One line per non-OK CVE. VULN entries (`[CRITICAL]`) appear before UNK
|
One line per non-OK CVE. VULN entries (`[CRITICAL]`) appear before UNK
|
||||||
|
|||||||
62
dist/doc/batch_prometheus.md
vendored
62
dist/doc/batch_prometheus.md
vendored
@@ -90,13 +90,16 @@ smc_build_info{version="25.30.0250400123",mode="live",run_as_root="true",paranoi
|
|||||||
|
|
||||||
Operating system and kernel metadata. Always value `1`.
|
Operating system and kernel metadata. Always value `1`.
|
||||||
|
|
||||||
Absent in offline mode when neither `uname -r` nor `uname -m` is available.
|
Absent entirely when none of `kernel_release`, `kernel_arch`, or
|
||||||
|
`hypervisor_host` can be determined (e.g. non-live mode with no VMM detection).
|
||||||
|
Each label is emitted only when its value is known; missing labels are
|
||||||
|
omitted rather than set to an empty string.
|
||||||
|
|
||||||
| Label | Values | Meaning |
|
| Label | Values | Meaning |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `kernel_release` | string | Output of `uname -r` (live mode only) |
|
| `kernel_release` | string | Output of `uname -r`; emitted only in live mode |
|
||||||
| `kernel_arch` | string | Output of `uname -m` (live mode only) |
|
| `kernel_arch` | string | Output of `uname -m`; emitted only in live mode |
|
||||||
| `hypervisor_host` | `true` / `false` | Whether this machine is detected as a hypervisor host (running KVM, Xen, VMware, etc.) |
|
| `hypervisor_host` | `true` / `false` | Whether this machine is detected as a hypervisor host (running KVM, Xen, VMware, etc.); absent when VMM detection did not run (e.g. `--no-hw`) |
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```
|
```
|
||||||
@@ -114,26 +117,47 @@ a malicious guest. Always prioritise remediation on hosts where
|
|||||||
### `smc_cpu_info`
|
### `smc_cpu_info`
|
||||||
|
|
||||||
CPU hardware and microcode metadata. Always value `1`. Absent when `--no-hw`
|
CPU hardware and microcode metadata. Always value `1`. Absent when `--no-hw`
|
||||||
is used.
|
is used or when `--arch-prefix` is set (host CPU info is suppressed to avoid
|
||||||
|
mixing with a different-arch target kernel).
|
||||||
|
|
||||||
|
Common labels (always emitted when the data is available):
|
||||||
|
|
||||||
| Label | Values | Meaning |
|
| Label | Values | Meaning |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `vendor` | string | CPU vendor (e.g. `Intel`, `AuthenticAMD`) |
|
| `vendor` | string | CPU vendor (e.g. `GenuineIntel`, `AuthenticAMD`, `HygonGenuine`, `ARM`) |
|
||||||
| `model` | string | CPU friendly name from `/proc/cpuinfo` |
|
| `model` | string | CPU friendly name from `/proc/cpuinfo` |
|
||||||
|
| `arch` | `x86` / `arm` | Architecture family; determines which arch-specific labels follow |
|
||||||
|
| `smt` | `true` / `false` | Whether SMT (HyperThreading) is currently enabled; absent if undeterminable |
|
||||||
|
| `microcode` | hex string | Installed microcode version (e.g. `0xf4`); absent if unreadable |
|
||||||
|
| `microcode_latest` | hex string | Latest known-good microcode version from the firmware database; absent if the CPU is not in the database |
|
||||||
|
| `microcode_up_to_date` | `true` / `false` | Whether `microcode == microcode_latest`; absent if either is unavailable |
|
||||||
|
| `microcode_blacklisted` | `true` / `false` | Whether the installed microcode is known to cause problems and should be rolled back; emitted whenever `microcode` is emitted |
|
||||||
|
|
||||||
|
x86-only labels (emitted when `arch="x86"`):
|
||||||
|
|
||||||
|
| Label | Values | Meaning |
|
||||||
|
|---|---|---|
|
||||||
| `family` | integer string | CPU family number |
|
| `family` | integer string | CPU family number |
|
||||||
| `model_id` | integer string | CPU model number |
|
| `model_id` | integer string | CPU model number |
|
||||||
| `stepping` | integer string | CPU stepping number |
|
| `stepping` | integer string | CPU stepping number |
|
||||||
| `cpuid` | hex string | Full CPUID value (e.g. `0x000906ed`); absent on some ARM CPUs |
|
| `cpuid` | hex string | Full CPUID value (e.g. `0x000906ed`) |
|
||||||
| `codename` | string | Intel CPU codename (e.g. `Coffee Lake`); absent on AMD and ARM |
|
| `codename` | string | Intel CPU codename (e.g. `Coffee Lake`); absent on AMD/Hygon |
|
||||||
| `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:**
|
ARM-only labels (emitted when `arch="arm"`):
|
||||||
|
|
||||||
|
| Label | Values | Meaning |
|
||||||
|
|---|---|---|
|
||||||
|
| `part_list` | string | Space-separated list of ARM part numbers across cores (e.g. `0xd0b 0xd05` on big.LITTLE) |
|
||||||
|
| `arch_list` | string | Space-separated list of ARM architecture levels across cores (e.g. `8 8`) |
|
||||||
|
|
||||||
|
**x86 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
|
smc_cpu_info{vendor="GenuineIntel",model="Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",arch="x86",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
|
||||||
|
```
|
||||||
|
|
||||||
|
**ARM example:**
|
||||||
|
```
|
||||||
|
smc_cpu_info{vendor="ARM",model="ARM v8 model 0xd0b",arch="arm",part_list="0xd0b 0xd05",arch_list="8 8",smt="false"} 1
|
||||||
```
|
```
|
||||||
|
|
||||||
**Microcode labels:**
|
**Microcode labels:**
|
||||||
@@ -352,9 +376,15 @@ queries. CVE checks that rely on hardware capability detection (`cap_*` flags,
|
|||||||
MSR reads) will report `unknown` status. `mode="no-hw"` in `smc_build_info`
|
MSR reads) will report `unknown` status. `mode="no-hw"` in `smc_build_info`
|
||||||
signals this.
|
signals this.
|
||||||
|
|
||||||
|
**Cross-arch inspection (`--arch-prefix`)**
|
||||||
|
When a cross-arch toolchain prefix is passed, the script suppresses the host
|
||||||
|
CPU metadata so it does not get mixed with data from a different-arch target
|
||||||
|
kernel: `smc_cpu_info` is not emitted, the same as under `--no-hw`.
|
||||||
|
|
||||||
**Hardware-only mode (`--hw-only`)**
|
**Hardware-only mode (`--hw-only`)**
|
||||||
Only hardware detection is performed; CVE checks are skipped. `smc_cpu_info`
|
Only hardware detection is performed; CVE checks are skipped. `smc_cpu_info`
|
||||||
is emitted but no `smc_vuln` metrics appear. `mode="hw-only"` in
|
is emitted but no `smc_vulnerability_status` metrics appear (and
|
||||||
|
`smc_vulnerable_count` / `smc_unknown_count` are `0`). `mode="hw-only"` in
|
||||||
`smc_build_info` signals this.
|
`smc_build_info` signals this.
|
||||||
|
|
||||||
**`--sysfs-only`**
|
**`--sysfs-only`**
|
||||||
|
|||||||
@@ -153,6 +153,12 @@ g_smc_cpu_info_line=''
|
|||||||
|
|
||||||
# CVE Registry: single source of truth for all CVE metadata.
|
# CVE Registry: single source of truth for all CVE metadata.
|
||||||
# Fields: cve_id|json_key_name|affected_var_suffix|complete_name_and_aliases
|
# Fields: cve_id|json_key_name|affected_var_suffix|complete_name_and_aliases
|
||||||
|
#
|
||||||
|
# Two ranges of placeholder IDs are reserved when no real CVE applies:
|
||||||
|
# CVE-0000-NNNN: permanent placeholder for supplementary checks (--extra only)
|
||||||
|
# that will never receive a real CVE (e.g. SLS, compile-time hardening).
|
||||||
|
# CVE-9999-NNNN: temporary placeholder for real vulnerabilities awaiting CVE
|
||||||
|
# assignment. Rename across the codebase once the real CVE is issued.
|
||||||
readonly CVE_REGISTRY='
|
readonly CVE_REGISTRY='
|
||||||
CVE-2017-5753|SPECTRE VARIANT 1|variant1|Spectre Variant 1, bounds check bypass
|
CVE-2017-5753|SPECTRE VARIANT 1|variant1|Spectre Variant 1, bounds check bypass
|
||||||
CVE-2017-5715|SPECTRE VARIANT 2|variant2|Spectre Variant 2, branch target injection
|
CVE-2017-5715|SPECTRE VARIANT 2|variant2|Spectre Variant 2, branch target injection
|
||||||
@@ -186,6 +192,7 @@ CVE-2025-40300|VMSCAPE|vmscape|VMScape, VM-exit stale branch prediction
|
|||||||
CVE-2023-28746|RFDS|rfds|Register File Data Sampling (RFDS)
|
CVE-2023-28746|RFDS|rfds|Register File Data Sampling (RFDS)
|
||||||
CVE-2024-45332|BPI|bpi|Branch Privilege Injection (BPI)
|
CVE-2024-45332|BPI|bpi|Branch Privilege Injection (BPI)
|
||||||
CVE-0000-0001|SLS|sls|Straight-Line Speculation (SLS)
|
CVE-0000-0001|SLS|sls|Straight-Line Speculation (SLS)
|
||||||
|
CVE-2025-54505|FPDSS|fpdss|FPDSS, AMD Zen1 Floating-Point Divider Stale Data Leak
|
||||||
'
|
'
|
||||||
|
|
||||||
# Derive the supported CVE list from the registry
|
# Derive the supported CVE list from the registry
|
||||||
|
|||||||
@@ -106,8 +106,9 @@ is_cpu_affected() {
|
|||||||
affected_srbds=''
|
affected_srbds=''
|
||||||
affected_mmio=''
|
affected_mmio=''
|
||||||
affected_sls=''
|
affected_sls=''
|
||||||
# DIV0, Zenbleed and Inception are all AMD specific, look for "is_amd" below:
|
# DIV0, FPDSS, Zenbleed and Inception are all AMD specific, look for "is_amd" below:
|
||||||
_set_immune div0
|
_set_immune div0
|
||||||
|
_set_immune fpdss
|
||||||
_set_immune zenbleed
|
_set_immune zenbleed
|
||||||
_set_immune inception
|
_set_immune inception
|
||||||
# TSA is AMD specific (Zen 3/4), look for "is_amd" below:
|
# TSA is AMD specific (Zen 3/4), look for "is_amd" below:
|
||||||
@@ -605,13 +606,23 @@ is_cpu_affected() {
|
|||||||
fi
|
fi
|
||||||
_set_immune variantl1tf
|
_set_immune variantl1tf
|
||||||
|
|
||||||
# DIV0 (Zen1 only)
|
# DIV0 (Zen1/Zen+)
|
||||||
# 77245f1c3c64 (v6.5, initial model list): family 0x17 models 0x00-0x2f, 0x50-0x5f
|
# 77245f1c3c64 (v6.5, initial model list): family 0x17 models 0x00-0x2f, 0x50-0x5f
|
||||||
# bfff3c6692ce (v6.8): moved to init_amd_zen1(), unconditional for all Zen1
|
# bfff3c6692ce (v6.8): moved to init_amd_zen1(), unconditional for all ZEN1-flagged CPUs
|
||||||
# All Zen1 CPUs are family 0x17, models 0x00-0x2f and 0x50-0x5f
|
# The kernel's X86_FEATURE_ZEN1 covers family 0x17 models 0x00-0x2f and 0x50-0x5f,
|
||||||
|
# which spans both Zen1 (Summit Ridge, Naples, Raven Ridge, Snowy Owl) and Zen+
|
||||||
|
# (Pinnacle Ridge, Picasso, Dali, Colfax) products -- all using the same divider silicon.
|
||||||
amd_legacy_erratum "$(amd_model_range 0x17 0x00 0x0 0x2f 0xf)" && _set_vuln div0
|
amd_legacy_erratum "$(amd_model_range 0x17 0x00 0x0 0x2f 0xf)" && _set_vuln div0
|
||||||
amd_legacy_erratum "$(amd_model_range 0x17 0x50 0x0 0x5f 0xf)" && _set_vuln div0
|
amd_legacy_erratum "$(amd_model_range 0x17 0x50 0x0 0x5f 0xf)" && _set_vuln div0
|
||||||
|
|
||||||
|
# FPDSS: same Zen1/Zen+ cohort as DIV0 (both applied unconditionally in init_amd_zen1()).
|
||||||
|
# e55d98e77561 (v7.1): unconditional in init_amd_zen1(); CVE-2025-54505 / AMD-SB-7053.
|
||||||
|
# AMD-SB-7053 only enumerates a subset (EPYC 7001, EPYC Embedded 3000, Athlon/Ryzen 3000
|
||||||
|
# with Radeon, Ryzen PRO 3000 with Radeon Vega), but the kernel mitigates the full
|
||||||
|
# ZEN1 cohort, so we flag all of it to match the kernel's behavior.
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
[ "$affected_div0" = 0 ] && _set_vuln fpdss
|
||||||
|
|
||||||
# Zenbleed
|
# Zenbleed
|
||||||
amd_legacy_erratum "$(amd_model_range 0x17 0x30 0x0 0x4f 0xf)" && _set_vuln zenbleed
|
amd_legacy_erratum "$(amd_model_range 0x17 0x30 0x0 0x4f 0xf)" && _set_vuln zenbleed
|
||||||
amd_legacy_erratum "$(amd_model_range 0x17 0x60 0x0 0x7f 0xf)" && _set_vuln zenbleed
|
amd_legacy_erratum "$(amd_model_range 0x17 0x60 0x0 0x7f 0xf)" && _set_vuln zenbleed
|
||||||
@@ -821,7 +832,7 @@ is_cpu_affected() {
|
|||||||
pr_debug "is_cpu_affected: final results: variant1=$affected_variant1 variant2=$affected_variant2 variant3=$affected_variant3 variant3a=$affected_variant3a"
|
pr_debug "is_cpu_affected: final results: variant1=$affected_variant1 variant2=$affected_variant2 variant3=$affected_variant3 variant3a=$affected_variant3a"
|
||||||
pr_debug "is_cpu_affected: final results: variant4=$affected_variant4 variantl1tf=$affected_variantl1tf msbds=$affected_msbds mfbds=$affected_mfbds"
|
pr_debug "is_cpu_affected: final results: variant4=$affected_variant4 variantl1tf=$affected_variantl1tf msbds=$affected_msbds mfbds=$affected_mfbds"
|
||||||
pr_debug "is_cpu_affected: final results: mlpds=$affected_mlpds mdsum=$affected_mdsum taa=$affected_taa itlbmh=$affected_itlbmh srbds=$affected_srbds"
|
pr_debug "is_cpu_affected: final results: mlpds=$affected_mlpds mdsum=$affected_mdsum taa=$affected_taa itlbmh=$affected_itlbmh srbds=$affected_srbds"
|
||||||
pr_debug "is_cpu_affected: final results: div0=$affected_div0 zenbleed=$affected_zenbleed inception=$affected_inception retbleed=$affected_retbleed tsa=$affected_tsa downfall=$affected_downfall reptar=$affected_reptar rfds=$affected_rfds its=$affected_its"
|
pr_debug "is_cpu_affected: final results: div0=$affected_div0 fpdss=$affected_fpdss zenbleed=$affected_zenbleed inception=$affected_inception retbleed=$affected_retbleed tsa=$affected_tsa downfall=$affected_downfall reptar=$affected_reptar rfds=$affected_rfds its=$affected_its"
|
||||||
pr_debug "is_cpu_affected: final results: vmscape=$affected_vmscape bpi=$affected_bpi sls=$affected_sls mmio=$affected_mmio"
|
pr_debug "is_cpu_affected: final results: vmscape=$affected_vmscape bpi=$affected_bpi sls=$affected_sls mmio=$affected_mmio"
|
||||||
}
|
}
|
||||||
affected_variantl1tf_sgx="$affected_variantl1tf"
|
affected_variantl1tf_sgx="$affected_variantl1tf"
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ while [ -n "${1:-}" ]; do
|
|||||||
case "$2" in
|
case "$2" in
|
||||||
help)
|
help)
|
||||||
echo "The following parameters are supported for --variant (can be used multiple times):"
|
echo "The following parameters are supported for --variant (can be used multiple times):"
|
||||||
echo "1, 2, 3, 3a, 4, msbds, mfbds, mlpds, mdsum, l1tf, taa, mcepsc, srbds, mmio, sbdr, sbds, drpw, div0, zenbleed, downfall, retbleed, inception, reptar, rfds, tsa, tsa-sq, tsa-l1, its, vmscape, bpi, sls"
|
echo "1, 2, 3, 3a, 4, msbds, mfbds, mlpds, mdsum, l1tf, taa, mcepsc, srbds, mmio, sbdr, sbds, drpw, div0, fpdss, zenbleed, downfall, retbleed, inception, reptar, rfds, tsa, tsa-sq, tsa-l1, its, vmscape, bpi, sls"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
1)
|
1)
|
||||||
@@ -245,6 +245,10 @@ while [ -n "${1:-}" ]; do
|
|||||||
opt_cve_list="$opt_cve_list CVE-2023-20588"
|
opt_cve_list="$opt_cve_list CVE-2023-20588"
|
||||||
opt_cve_all=0
|
opt_cve_all=0
|
||||||
;;
|
;;
|
||||||
|
fpdss)
|
||||||
|
opt_cve_list="$opt_cve_list CVE-2025-54505"
|
||||||
|
opt_cve_all=0
|
||||||
|
;;
|
||||||
zenbleed)
|
zenbleed)
|
||||||
opt_cve_list="$opt_cve_list CVE-2023-20593"
|
opt_cve_list="$opt_cve_list CVE-2023-20593"
|
||||||
opt_cve_all=0
|
opt_cve_all=0
|
||||||
|
|||||||
@@ -15,15 +15,17 @@ _prom_escape() {
|
|||||||
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | tr '\n' ' '
|
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | tr '\n' ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
# Convert a shell capability value to a JSON token
|
# Convert a shell capability value to a JSON boolean token
|
||||||
# Args: $1=value (1=true, 0=false, -1/empty=null, other string=quoted string)
|
# Args: $1=value (1=true, 0=false, -1/empty=null, any other non-empty string=true)
|
||||||
# Prints: JSON token
|
# Prints: JSON token (true/false/null)
|
||||||
|
# Note: capability variables can be set to arbitrary strings internally to carry
|
||||||
|
# detection-path context (e.g. cap_ssbd='Intel SSBD'); for the JSON output those
|
||||||
|
# are normalized to true so consumers see a clean boolean | null type.
|
||||||
_json_cap() {
|
_json_cap() {
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
1) printf 'true' ;;
|
|
||||||
0) printf 'false' ;;
|
0) printf 'false' ;;
|
||||||
-1 | '') printf 'null' ;;
|
-1 | '') printf 'null' ;;
|
||||||
*) printf '"%s"' "$(_json_escape "$1")" ;;
|
*) printf 'true' ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +128,7 @@ _build_json_system() {
|
|||||||
# Sets: g_json_cpu
|
# Sets: g_json_cpu
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
_build_json_cpu() {
|
_build_json_cpu() {
|
||||||
local cpuid_hex codename caps arch_sub arch_type
|
local cpuid_hex codename caps arch_sub arch_type sbpb_norm
|
||||||
if [ -n "${cpu_cpuid:-}" ]; then
|
if [ -n "${cpu_cpuid:-}" ]; then
|
||||||
cpuid_hex=$(printf '0x%08x' "$cpu_cpuid")
|
cpuid_hex=$(printf '0x%08x' "$cpu_cpuid")
|
||||||
else
|
else
|
||||||
@@ -137,6 +139,15 @@ _build_json_cpu() {
|
|||||||
codename=$(get_intel_codename 2>/dev/null || true)
|
codename=$(get_intel_codename 2>/dev/null || true)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# cap_sbpb uses non-standard encoding (1=YES, 2=NO, 3=UNKNOWN) because the
|
||||||
|
# CVE-2023-20569 check distinguishes the unknown case. Normalize for JSON.
|
||||||
|
case "${cap_sbpb:-}" in
|
||||||
|
1) sbpb_norm=1 ;;
|
||||||
|
2) sbpb_norm=0 ;;
|
||||||
|
3) sbpb_norm=-1 ;;
|
||||||
|
*) sbpb_norm='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
# Determine architecture type and build the arch-specific sub-object
|
# Determine architecture type and build the arch-specific sub-object
|
||||||
case "${cpu_vendor:-}" in
|
case "${cpu_vendor:-}" in
|
||||||
GenuineIntel | AuthenticAMD | HygonGenuine)
|
GenuineIntel | AuthenticAMD | HygonGenuine)
|
||||||
@@ -190,7 +201,7 @@ _build_json_cpu() {
|
|||||||
"$(_json_cap "${cap_tsa_l1_no:-}")" \
|
"$(_json_cap "${cap_tsa_l1_no:-}")" \
|
||||||
"$(_json_cap "${cap_verw_clear:-}")" \
|
"$(_json_cap "${cap_verw_clear:-}")" \
|
||||||
"$(_json_cap "${cap_autoibrs:-}")" \
|
"$(_json_cap "${cap_autoibrs:-}")" \
|
||||||
"$(_json_cap "${cap_sbpb:-}")" \
|
"$(_json_cap "$sbpb_norm")" \
|
||||||
"$(_json_cap "${cap_avx2:-}")" \
|
"$(_json_cap "${cap_avx2:-}")" \
|
||||||
"$(_json_cap "${cap_avx512:-}")")
|
"$(_json_cap "${cap_avx512:-}")")
|
||||||
arch_sub=$(printf '{"family":%s,"model":%s,"stepping":%s,"cpuid":%s,"platform_id":%s,"hybrid":%s,"codename":%s,"capabilities":%s}' \
|
arch_sub=$(printf '{"family":%s,"model":%s,"stepping":%s,"cpuid":%s,"platform_id":%s,"hybrid":%s,"codename":%s,"capabilities":%s}' \
|
||||||
|
|||||||
151
src/vulns/CVE-2025-54505.sh
Normal file
151
src/vulns/CVE-2025-54505.sh
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
# vim: set ts=4 sw=4 sts=4 et:
|
||||||
|
###############################
|
||||||
|
# CVE-2025-54505, FPDSS, AMD Zen1 Floating-Point Divider Stale Data Leak
|
||||||
|
|
||||||
|
check_CVE_2025_54505() {
|
||||||
|
check_cve 'CVE-2025-54505'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print remediation advice for FPDSS when reporting VULN
|
||||||
|
# Callers: check_CVE_2025_54505_linux
|
||||||
|
_cve_2025_54505_explain_fix() {
|
||||||
|
explain "Update your kernel to one that carries commit e55d98e77561 (\"x86/CPU: Fix FPDSS on Zen1\", mainline Linux 7.1),\n " \
|
||||||
|
"or the equivalent backport from your distribution. The kernel sets bit 9 of MSR 0xc0011028 unconditionally on\n " \
|
||||||
|
"every Zen1 CPU at boot, which disables the hardware optimization responsible for the leak.\n " \
|
||||||
|
"To manually mitigate the issue right now, you may use the following command:\n " \
|
||||||
|
"\`wrmsr -a 0xc0011028 \$((\$(rdmsr -c 0xc0011028) | (1<<9)))\`,\n " \
|
||||||
|
"however note that this manual mitigation will only be active until the next reboot.\n " \
|
||||||
|
"No microcode update is required: the chicken bit is present on every Zen1 CPU."
|
||||||
|
}
|
||||||
|
|
||||||
|
check_CVE_2025_54505_linux() {
|
||||||
|
local status sys_interface_available msg kernel_mitigated dmesg_fpdss msr_fpdss ret
|
||||||
|
status=UNK
|
||||||
|
sys_interface_available=0
|
||||||
|
msg=''
|
||||||
|
# No sysfs interface exists for this vulnerability (no /sys/devices/system/cpu/vulnerabilities/fpdss).
|
||||||
|
# sys_interface_available stays 0.
|
||||||
|
#
|
||||||
|
# Kernel source inventory for FPDSS, traced via git blame:
|
||||||
|
#
|
||||||
|
# --- sysfs messages ---
|
||||||
|
# none: this vulnerability has no sysfs entry
|
||||||
|
#
|
||||||
|
# --- Kconfig symbols ---
|
||||||
|
# none: the mitigation is unconditional, not configurable (no CONFIG_* knob)
|
||||||
|
#
|
||||||
|
# --- kernel functions (for $opt_map / System.map) ---
|
||||||
|
# none: the fix is two inline lines in init_amd_zen1(), no dedicated function
|
||||||
|
#
|
||||||
|
# --- dmesg ---
|
||||||
|
# e55d98e77561 (v7.1, initial fix): "AMD Zen1 FPDSS bug detected, enabling mitigation."
|
||||||
|
# (printed via pr_notice_once on every Zen1 CPU)
|
||||||
|
#
|
||||||
|
# --- /proc/cpuinfo bugs field ---
|
||||||
|
# none: no X86_BUG_FPDSS flag defined; no cpuinfo exposure
|
||||||
|
#
|
||||||
|
# --- MSR ---
|
||||||
|
# e55d98e77561 (v7.1): MSR_AMD64_FP_CFG = 0xc0011028, bit 9 = ZEN1_DENORM_FIX_BIT
|
||||||
|
# kernel calls msr_set_bit() unconditionally on any Zen1 CPU in init_amd_zen1().
|
||||||
|
# The bit is present in Zen1 silicon independently of microcode (no microcode
|
||||||
|
# revision gate in the kernel, unlike Zenbleed which uses amd_zenbleed_microcode[]).
|
||||||
|
#
|
||||||
|
# --- CPU affection logic (for is_cpu_affected) ---
|
||||||
|
# e55d98e77561 (v7.1): applied unconditionally in init_amd_zen1(), i.e. all Zen1
|
||||||
|
# AMD: family 0x17 models 0x00-0x2f, 0x50-0x5f (same cohort as DIV0)
|
||||||
|
# vendor scope: AMD only (Zen1 microarchitecture)
|
||||||
|
#
|
||||||
|
# --- stable backports ---
|
||||||
|
# as of this writing, no stable/LTS backport has landed; only mainline (Linux 7.1).
|
||||||
|
|
||||||
|
if [ "$opt_sysfs_only" != 1 ]; then
|
||||||
|
pr_info_nol "* Kernel supports FPDSS mitigation: "
|
||||||
|
kernel_mitigated=''
|
||||||
|
if [ -n "$g_kernel_err" ]; then
|
||||||
|
pstatus yellow UNKNOWN "$g_kernel_err"
|
||||||
|
elif is_x86_kernel && grep -q 'AMD Zen1 FPDSS bug detected' "$g_kernel"; then
|
||||||
|
kernel_mitigated="found FPDSS mitigation message in kernel image"
|
||||||
|
pstatus green YES "$kernel_mitigated"
|
||||||
|
else
|
||||||
|
pstatus yellow NO
|
||||||
|
fi
|
||||||
|
|
||||||
|
pr_info_nol "* FPDSS mitigation enabled and active: "
|
||||||
|
msr_fpdss=''
|
||||||
|
dmesg_fpdss=''
|
||||||
|
if [ "$g_mode" = live ] && is_x86_cpu && is_cpu_affected "$cve"; then
|
||||||
|
# guard with is_cpu_affected to avoid #GP on non-Zen1 CPUs where 0xc0011028 is undefined
|
||||||
|
read_msr 0xc0011028
|
||||||
|
ret=$?
|
||||||
|
if [ "$ret" = "$READ_MSR_RET_OK" ]; then
|
||||||
|
if [ $((ret_read_msr_value_lo >> 9 & 1)) -eq 1 ]; then
|
||||||
|
msr_fpdss=1
|
||||||
|
pstatus green YES "ZEN1_DENORM_FIX_BIT set in FP_CFG MSR"
|
||||||
|
else
|
||||||
|
msr_fpdss=0
|
||||||
|
pstatus yellow NO "ZEN1_DENORM_FIX_BIT is cleared in FP_CFG MSR"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# MSR unreadable (lockdown, no msr module, etc.): fall back to dmesg
|
||||||
|
dmesg_grep 'AMD Zen1 FPDSS bug detected'
|
||||||
|
ret=$?
|
||||||
|
if [ "$ret" -eq 0 ]; then
|
||||||
|
dmesg_fpdss=1
|
||||||
|
pstatus green YES "FPDSS mitigation message found in dmesg"
|
||||||
|
elif [ "$ret" -eq 2 ]; then
|
||||||
|
pstatus yellow UNKNOWN "couldn't read MSR and dmesg is truncated"
|
||||||
|
else
|
||||||
|
pstatus yellow UNKNOWN "couldn't read MSR and no FPDSS message in dmesg"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [ "$g_mode" = live ]; then
|
||||||
|
pstatus blue N/A "CPU is incompatible"
|
||||||
|
else
|
||||||
|
pstatus blue N/A "not testable in no-runtime mode"
|
||||||
|
fi
|
||||||
|
elif [ "$sys_interface_available" = 0 ]; then
|
||||||
|
msg="/sys vulnerability interface use forced, but it's not available!"
|
||||||
|
status=UNK
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! is_cpu_affected "$cve"; then
|
||||||
|
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
||||||
|
elif [ -z "$msg" ]; then
|
||||||
|
if [ "$opt_sysfs_only" != 1 ]; then
|
||||||
|
if [ "$g_mode" = live ]; then
|
||||||
|
if [ "$msr_fpdss" = 1 ] || [ "$dmesg_fpdss" = 1 ]; then
|
||||||
|
pvulnstatus "$cve" OK "ZEN1_DENORM_FIX_BIT is set in FP_CFG MSR, mitigation is active"
|
||||||
|
elif [ "$msr_fpdss" = 0 ]; then
|
||||||
|
pvulnstatus "$cve" VULN "ZEN1_DENORM_FIX_BIT is cleared in FP_CFG MSR, FPDSS can leak data between threads"
|
||||||
|
_cve_2025_54505_explain_fix
|
||||||
|
elif [ -n "$kernel_mitigated" ]; then
|
||||||
|
# MSR unreadable at runtime, but kernel image carries the mitigation code
|
||||||
|
# and init_amd_zen1() sets the bit unconditionally, so mitigation is active
|
||||||
|
pvulnstatus "$cve" OK "kernel image carries FPDSS mitigation code (init_amd_zen1 sets the MSR bit unconditionally at boot)"
|
||||||
|
else
|
||||||
|
pvulnstatus "$cve" VULN "your kernel doesn't support FPDSS mitigation"
|
||||||
|
_cve_2025_54505_explain_fix
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -n "$kernel_mitigated" ]; then
|
||||||
|
pvulnstatus "$cve" OK "Mitigation: FPDSS message found in kernel image"
|
||||||
|
else
|
||||||
|
pvulnstatus "$cve" VULN "your kernel doesn't support FPDSS mitigation"
|
||||||
|
_cve_2025_54505_explain_fix
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
pvulnstatus "$cve" "$status" "no sysfs interface available for this CVE, use --no-sysfs to check"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
pvulnstatus "$cve" "$status" "$msg"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_CVE_2025_54505_bsd() {
|
||||||
|
if ! is_cpu_affected "$cve"; then
|
||||||
|
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
||||||
|
else
|
||||||
|
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
|
||||||
|
fi
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user