Compare commits

..

1 Commits

Author SHA1 Message Date
Stéphane Lesimple
c64d4bb481 enh: guard x86/arm specific checks in kernel/cpu for the proper arch 2026-04-10 18:39:35 +02:00
40 changed files with 453 additions and 1265 deletions

36
.github/workflows/autoupdate.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
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

View File

@@ -1 +1 @@
32 31

33
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
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) }}

View File

@@ -105,8 +105,8 @@ The entire tool is a single bash script with no external script dependencies. Ke
- **Output/logging functions** (~line 253): `pr_warn`, `pr_info`, `pr_verbose`, `pr_debug`, `explain`, `pstatus`, `pvulnstatus` - verbosity-aware output with color support - **Output/logging functions** (~line 253): `pr_warn`, `pr_info`, `pr_verbose`, `pr_debug`, `explain`, `pstatus`, `pvulnstatus` - verbosity-aware output with color support
- **CPU detection** (~line 2171): `parse_cpu_details`, `is_intel`/`is_amd`/`is_hygon`, `read_cpuid`, `read_msr`, `is_cpu_smt_enabled` - hardware identification via CPUID/MSR registers - **CPU detection** (~line 2171): `parse_cpu_details`, `is_intel`/`is_amd`/`is_hygon`, `read_cpuid`, `read_msr`, `is_cpu_smt_enabled` - hardware identification via CPUID/MSR registers
- **Kernel architecture detection** (`src/libs/365_kernel_arch.sh`): `is_arm_kernel`/`is_x86_kernel` - detects the **target kernel's** architecture (not the host CPU) using kernel artifacts (System.map symbols, kconfig, kernel image), with `cpu_vendor` as a fast path for live mode. Results are cached in `g_kernel_arch`. Use these helpers to guard arch-specific kernel/kconfig/System.map checks and to select the appropriate verdict messages. In no-hw mode, the target kernel may differ from the host CPU architecture. - **Kernel architecture detection** (`src/libs/365_kernel_arch.sh`): `is_arm_kernel`/`is_x86_kernel` - detects the target kernel's architecture (not the host CPU) using kernel artifacts (System.map symbols, kconfig, kernel image), with `cpu_vendor` as a fast path for live mode. Results are cached in `g_kernel_arch`. Use these helpers to guard arch-specific kernel/kconfig/System.map checks and to select the appropriate verdict messages
- **CPU architecture detection** (`src/libs/360_cpu_smt.sh`): `is_x86_cpu`/`is_arm_cpu` - detects the **host CPU's** architecture via `cpu_vendor`. Use these to gate hardware operations (CPUID, MSR, microcode) that require the physical CPU to be present. Always use positive logic: `if is_x86_cpu` (not `if ! is_arm_cpu`). These two sets of helpers are independent — a vuln check may need both, each guarding different lines. - **CPU architecture detection** (`src/libs/360_cpu_smt.sh`): `is_x86_cpu`/`is_arm_cpu` - detects the host CPU's architecture via `cpu_vendor`. Use these to gate hardware operations (CPUID, MSR, microcode). Always use positive logic: `if is_x86_cpu` (not `if ! is_arm_cpu`)
- **Microcode database** (embedded): Intel/AMD microcode version lookup via `read_mcedb`/`read_inteldb`; updated automatically via `.github/workflows/autoupdate.yml` - **Microcode database** (embedded): Intel/AMD microcode version lookup via `read_mcedb`/`read_inteldb`; updated automatically via `.github/workflows/autoupdate.yml`
- **Kernel analysis** (~line 1568): `extract_kernel`, `try_decompress` - extracts and inspects kernel images (handles gzip, bzip2, xz, lz4, zstd compression) - **Kernel analysis** (~line 1568): `extract_kernel`, `try_decompress` - extracts and inspects kernel images (handles gzip, bzip2, xz, lz4, zstd compression)
- **Vulnerability checks**: 19 `check_CVE_<year>_<number>()` functions, each with `_linux()` and `_bsd()` variants. Uses whitelist logic (assumes affected unless proven otherwise) - **Vulnerability checks**: 19 `check_CVE_<year>_<number>()` functions, each with `_linux()` and `_bsd()` variants. Uses whitelist logic (assumes affected unless proven otherwise)
@@ -118,7 +118,7 @@ The entire tool is a single bash script with no external script dependencies. Ke
Two JSON formats are available via `--batch`: Two JSON formats are available via `--batch`:
- **`--batch json`** (comprehensive): A top-level object with five sections: - **`--batch json`** (comprehensive): A top-level object with five sections:
- `meta` — script version, format version, timestamp, `mode` (`live`, `no-runtime`, `no-hw`, `hw-only`), run mode flags (`run_as_root`, `reduced_accuracy`, `mocked`, `paranoid`, `sysfs_only`, `extra`) - `meta` — script version, format version, timestamp, run mode flags (`run_as_root`, `reduced_accuracy`, `mocked`, `paranoid`, `sysfs_only`, `extra`)
- `system` — kernel release/version/arch/cmdline, CPU count, SMT status, hypervisor host detection - `system` — kernel release/version/arch/cmdline, CPU count, SMT status, hypervisor host detection
- `cpu``arch` discriminator (`x86` or `arm`), vendor, friendly name, then an arch-specific sub-object (`cpu.x86` or `cpu.arm`) with identification fields (family/model/stepping/CPUID/codename for x86; part\_list/arch\_list for ARM) and a `capabilities` sub-object containing hardware flags as booleans/nulls - `cpu``arch` discriminator (`x86` or `arm`), vendor, friendly name, then an arch-specific sub-object (`cpu.x86` or `cpu.arm`) with identification fields (family/model/stepping/CPUID/codename for x86; part\_list/arch\_list for ARM) and a `capabilities` sub-object containing hardware flags as booleans/nulls
- `cpu_microcode``installed_version`, `latest_version`, `microcode_up_to_date`, `is_blacklisted`, firmware DB source/info - `cpu_microcode``installed_version`, `latest_version`, `microcode_up_to_date`, `is_blacklisted`, firmware DB source/info
@@ -161,7 +161,7 @@ This works because the kernel always has direct access to CPUID (it doesn't need
**Rules:** **Rules:**
- This is strictly a fallback: `read_cpuid` via `/dev/cpu/N/cpuid` remains the primary method. - This is strictly a fallback: `read_cpuid` via `/dev/cpu/N/cpuid` remains the primary method.
- Only use it when `read_cpuid` returned `READ_CPUID_RET_ERR` (device unavailable), **never** when it returned `READ_CPUID_RET_KO` (device available but bit is 0 — meaning the CPU/hypervisor explicitly reports the feature as absent). - Only use it when `read_cpuid` returned `READ_CPUID_RET_ERR` (device unavailable), **never** when it returned `READ_CPUID_RET_KO` (device available but bit is 0 — meaning the CPU/hypervisor explicitly reports the feature as absent).
- Only in live mode (`$g_mode = live`), since `/proc/cpuinfo` is not available in other modes. - Only in live mode (`$opt_runtime = 1`), since `/proc/cpuinfo` is not available in no-runtime mode.
- Only for CPUID bits that the kernel exposes as `/proc/cpuinfo` flags. Not all bits have a corresponding flag — only those listed in the kernel's `capflags.c`. If a bit has no `/proc/cpuinfo` flag, no fallback is possible. - Only for CPUID bits that the kernel exposes as `/proc/cpuinfo` flags. Not all bits have a corresponding flag — only those listed in the kernel's `capflags.c`. If a bit has no `/proc/cpuinfo` flag, no fallback is possible.
- The fallback depends on the running kernel being recent enough to know about the CPUID bit in question. An older kernel won't expose a flag it doesn't know about, so the fallback will silently not trigger — which is fine (we just stay at UNKNOWN, same as the ERR case without fallback). - The fallback depends on the running kernel being recent enough to know about the CPUID bit in question. An older kernel won't expose a flag it doesn't know about, so the fallback will silently not trigger — which is fine (we just stay at UNKNOWN, same as the ERR case without fallback).
@@ -184,7 +184,7 @@ read_cpuid 0x7 0x0 $EDX 31 1 1
ret=$? ret=$?
if [ $ret = $READ_CPUID_RET_OK ]; then if [ $ret = $READ_CPUID_RET_OK ]; then
cap_ssbd='Intel SSBD' cap_ssbd='Intel SSBD'
elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$g_mode" = live ]; then elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw ssbd; then if grep ^flags "$g_procfs/cpuinfo" | grep -qw ssbd; then
cap_ssbd='Intel SSBD (cpuinfo)' cap_ssbd='Intel SSBD (cpuinfo)'
@@ -291,12 +291,7 @@ 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`. When no real CVE applies, two placeholder ranges are reserved: Create `src/vulns/CVE-YYYY-NNNNN.sh`. The file header must follow this exact format:
- **`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 (`###############################`)
@@ -401,10 +396,9 @@ This is where the real detection lives. Check for mitigations at each layer:
Use **positive logic** — always `if is_x86_kernel` (not `if ! is_arm_kernel`) and `if is_x86_cpu` (not `if ! is_arm_cpu`). This ensures unknown architectures (MIPS, RISC-V, PowerPC) are handled safely by defaulting to "skip" rather than "execute." Use **positive logic** — always `if is_x86_kernel` (not `if ! is_arm_kernel`) and `if is_x86_cpu` (not `if ! is_arm_cpu`). This ensures unknown architectures (MIPS, RISC-V, PowerPC) are handled safely by defaulting to "skip" rather than "execute."
Two sets of helpers serve different purposes — in no-hw mode the host CPU and the kernel being inspected can be different architectures, so the correct guard depends on what is being checked: Two sets of helpers serve different purposes:
- **`is_x86_kernel`/`is_arm_kernel`**: Gate checks that inspect **kernel artifacts** (kernel image strings, kconfig, System.map). These detect the architecture of the target kernel, not the host, so they work correctly in offline/no-hw mode when analyzing a foreign kernel. - **`is_x86_kernel`/`is_arm_kernel`**: Gate kernel artifact checks (kernel image strings, kconfig, System.map).
- **`is_x86_cpu`/`is_arm_cpu`**: Gate **hardware operations** that require the host CPU to be a given architecture (CPUID, MSR reads, `/proc/cpuinfo` flags, microcode version checks). These always reflect the running host CPU. - **`is_x86_cpu`/`is_arm_cpu`**: Gate hardware operations (CPUID, MSR, `/proc/cpuinfo` flags).
- Within a single vuln check, you may need **both** guards independently — e.g. `is_x86_cpu` for the microcode/MSR check and `is_x86_kernel` for the kernel image grep, not one wrapping the other.
Example: Example:
```sh ```sh
@@ -423,16 +417,16 @@ This is where the real detection lives. Check for mitigations at each layer:
``` ```
The same applies to Phase 4 verdict messages: when the explanation or remediation advice differs between architectures (e.g. "CPU microcode update" vs "firmware/kernel update"), branch on `is_arm_kernel`/`is_x86_kernel` rather than on `cpu_vendor`, because `cpu_vendor` reflects the host, not the target kernel. The same applies to Phase 4 verdict messages: when the explanation or remediation advice differs between architectures (e.g. "CPU microcode update" vs "firmware/kernel update"), branch on `is_arm_kernel`/`is_x86_kernel` rather than on `cpu_vendor`, because `cpu_vendor` reflects the host, not the target kernel.
- **Runtime state** (live mode only): Read MSRs, check cpuinfo flags, parse dmesg, inspect debugfs. All runtime-only checks — including `/proc/cpuinfo` flags — must be guarded by `if [ "$g_mode" = live ]`, both when collecting the evidence in Phase 2 and when using it in Phase 4. In Phase 4, use explicit live/non-live branches so that live-only variables (e.g. cpuinfo flags, MSR values) are never referenced in the non-live path. - **Runtime state** (live mode only): Read MSRs, check cpuinfo flags, parse dmesg, inspect debugfs. All runtime-only checks — including `/proc/cpuinfo` flags — must be guarded by `if [ "$opt_runtime" = 1 ]`, both when collecting the evidence in Phase 2 and when using it in Phase 4. In Phase 4, use explicit live/no-runtime branches so that live-only variables (e.g. cpuinfo flags, MSR values) are never referenced in the no-runtime path.
```sh ```sh
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
read_msr 0xADDRESS read_msr 0xADDRESS
ret=$? ret=$?
if [ "$ret" = "$READ_MSR_RET_OK" ]; then if [ "$ret" = "$READ_MSR_RET_OK" ]; then
# check specific bits in ret_read_msr_value_lo / ret_read_msr_value_hi # check specific bits in ret_read_msr_value_lo / ret_read_msr_value_hi
fi fi
else else
pstatus blue N/A "not testable in non-live mode" pstatus blue N/A "not testable in no-runtime mode"
fi fi
``` ```
@@ -817,7 +811,7 @@ CVEs that need VMM context should call `check_has_vmm` early in their `_linux()`
- **Never hardcode kernel or microcode versions** - detect capabilities directly (design principles 2 and 3). Exception: when a microcode fix has no detectable indicator, hardcode fixing versions per CPU (see principle 3). - **Never hardcode kernel or microcode versions** - detect capabilities directly (design principles 2 and 3). Exception: when a microcode fix has no detectable indicator, hardcode fixing versions per CPU (see principle 3).
- **Assume affected by default** - only mark a CPU as unaffected when there is positive evidence (design principle 4). - **Assume affected by default** - only mark a CPU as unaffected when there is positive evidence (design principle 4).
- **Always handle both live and non-live modes** use `$g_mode` to branch (`if [ "$g_mode" = live ]`), and print `N/A "not testable in non-live mode"` for runtime-only checks when not in live mode. Inside CVE checks, `live` is the only mode with runtime access (hw-only skips the CVE loop). Outside CVE checks (e.g. `check_cpu`), use the `has_runtime` helper which returns true for both `live` and `hw-only`. - **Always handle both live and no-runtime modes** - use `$opt_runtime` to branch, and print `N/A "not testable in no-runtime mode"` for runtime-only checks when in no-runtime mode.
- **Use `explain()`** when reporting VULN to give actionable remediation advice (see "Cross-Cutting Features" above). - **Use `explain()`** when reporting VULN to give actionable remediation advice (see "Cross-Cutting Features" above).
- **Handle `--paranoid` and `--vmm`** when the CVE has stricter mitigation tiers or VMM-specific aspects (see "Cross-Cutting Features" above). - **Handle `--paranoid` and `--vmm`** when the CVE has stricter mitigation tiers or VMM-specific aspects (see "Cross-Cutting Features" above).
- **Keep JSON output in sync** - when adding new `cap_*` variables, add them to `_build_json_cpu()` in `src/libs/250_output_emitters.sh` (see Step 2 JSON note above). Per-CVE fields are handled automatically. - **Keep JSON output in sync** - when adding new `cap_*` variables, add them to `_build_json_cpu()` in `src/libs/250_output_emitters.sh` (see Step 2 JSON note above). Per-CVE fields are handled automatically.

36
dist/README.md vendored
View File

@@ -38,15 +38,6 @@ 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
The following entries are ARM64 silicon errata that the kernel actively works around. They have no assigned CVE; they are tracked only by ARM's erratum numbers. Select them with `--errata <number>` or the associated `--variant` mnemonic.
ID | Name | Affected cores
-- | ---- | --------------
CVE-0001-0001 | Speculative AT TLB corruption (errata 1165522, 1319367, 1319537, 1530923) | Cortex-A55/A57/A72/A76
CVE-0001-0002 | Speculative unprivileged load (errata 2966298, 3117295) | Cortex-A510/A520
CVE-0001-0003 | MSR SSBS not self-synchronizing (erratum 3194386 + siblings) | Cortex-A76/A77/A78/A78C/A710/A715/A720/A720AE/A725, X1/X1C/X2/X3/X4/X925, Neoverse-N1/N2/N3/V1/V2/V3/V3AE
## Am I at risk? ## Am I at risk?
@@ -86,7 +77,6 @@ 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.
@@ -217,10 +207,6 @@ 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
@@ -280,23 +266,23 @@ In **Hardware-only** mode, the script only reports CPU information and per-CVE h
- Get the latest version of the script using `curl` *or* `wget` - Get the latest version of the script using `curl` *or* `wget`
```bash ```bash
curl -L https://meltdown.ovh -o spectre-meltdown-checker.sh curl -L https://meltdown.ovh -o spectre-meltdown-checker.sh
wget https://meltdown.ovh -O spectre-meltdown-checker.sh wget https://meltdown.ovh -O spectre-meltdown-checker.sh
``` ```
- Inspect the script. You never blindly run scripts you downloaded from the Internet, do you? - Inspect the script. You never blindly run scripts you downloaded from the Internet, do you?
```bash ```bash
vim spectre-meltdown-checker.sh vim spectre-meltdown-checker.sh
``` ```
- When you're ready, run the script as root - When you're ready, run the script as root
```bash ```bash
chmod +x spectre-meltdown-checker.sh chmod +x spectre-meltdown-checker.sh
sudo ./spectre-meltdown-checker.sh sudo ./spectre-meltdown-checker.sh
``` ```
### Using a docker container ### Using a docker container

View File

@@ -124,17 +124,6 @@ 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)
@@ -307,13 +296,3 @@ A weakness in AMD's microcode signature verification (AES-CMAC hash) allows load
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. 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. **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.
## No CVE — Jump Conditional Code (JCC) Erratum
- **Issue:** [#329](https://github.com/speed47/spectre-meltdown-checker/issues/329)
- **Intel whitepaper:** [Mitigations for Jump Conditional Code Erratum](https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf)
- **Affected CPUs:** Intel 6th through 10th generation Core and Xeon processors (Skylake through Cascade Lake)
A microarchitectural correctness erratum where a conditional jump instruction that straddles or ends at a 64-byte instruction fetch boundary can corrupt the branch predictor state, potentially causing incorrect execution. Intel addressed this in a November 2019 microcode update. Compilers and assemblers (GCC, LLVM, binutils) also introduced alignment options (`-mbranch-alignment`, `-x86-branches-within-32B-boundaries`) to pad jump instructions away from boundary conditions, preserving performance on CPUs with updated microcode.
**Why out of scope:** The JCC erratum is a microarchitectural correctness bug, not a transient or speculative execution side-channel vulnerability. No CVE was ever assigned. Red Hat noted that privilege escalation "has not been ruled out" but made no definitive security finding, and no exploit has been demonstrated. There is no Linux sysfs entry, no CPUID bit, and no MSR flag exposing the mitigation status. The microcode fix introduces no detectable hardware indicator, so checking for it would require maintaining a per-CPU-stepping minimum microcode version table (the design principle 3 exception) — costly to maintain without a CVE anchor or confirmed exploitability to justify the ongoing work. The kernel compiler mitigation is a build-time-only change (instruction alignment) with no observable runtime state.

View File

@@ -102,9 +102,7 @@ boundaries by a malicious guest. Prioritise remediation where
### `cpu` ### `cpu`
CPU hardware identification. `null` when `--no-hw` is active, or when CPU hardware identification. `null` when `--no-hw` is active.
`--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
@@ -142,7 +140,7 @@ fields from the other architecture.
#### `cpu.x86.capabilities` #### `cpu.x86.capabilities`
Every capability is a **tri-state**: `true` (present), `false` (absent), or 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 `null` (not applicable or could not be read, e.g. when not root or on AMD for
Intel-specific features). Intel-specific features).
@@ -240,7 +238,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, or if the CVE's check read sysfs in silent/quiet mode (raw message is still captured in `sysfs_message`) | | `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 | | `sysfs_message` | string \| null | | Raw text from the sysfs file (e.g. `"Mitigation: PTI"`); null if sysfs was not consulted |
#### Status values #### Status values

View File

@@ -127,7 +127,7 @@
}, },
"cpu": { "cpu": {
"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.", "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": [ "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. Every value is tri-state: true=present, false=absent, null=not applicable or unreadable.", "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", "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": "IBRS supported (via SPEC_CTRL, IBRS_SUPPORT, or cpuinfo fallback)" }, "ibrs": { "type": ["boolean", "null"], "description": "Indirect Branch Restricted Speculation" },
"ibpb": { "type": ["boolean", "null"], "description": "IBPB supported (via SPEC_CTRL, IBPB_SUPPORT, or cpuinfo fallback)" }, "ibpb": { "type": ["boolean", "null"], "description": "Indirect Branch Prediction Barrier" },
"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": "STIBP supported (Intel/AMD/HYGON or cpuinfo fallback)" }, "stibp": { "type": ["boolean", "null"], "description": "Single Thread Indirect Branch Predictors" },
"ssbd": { "type": ["boolean", "null"], "description": "SSBD supported (SPEC_CTRL, VIRT_SPEC_CTRL, non-architectural MSR, or cpuinfo fallback)" }, "ssbd": { "type": ["boolean", "null"], "description": "Speculative Store Bypass Disable" },
"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): 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)" }, "sbpb": { "type": ["boolean", "null"], "description": "Selective Branch Predictor Barrier (AMD Inception mitigation)" },
"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)" }
} }

View File

@@ -51,7 +51,6 @@ 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)
@@ -60,19 +59,15 @@ Never parsed by the monitoring core; safe to add or reorder.
#### Context notes #### Context notes
Printed before per-CVE details when applicable. Notes are emitted in this Printed before per-CVE details when applicable:
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 detected as a VM host (KVM, Xen, VMware…) | | `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 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

View File

@@ -59,7 +59,7 @@ Script metadata. Always value `1`; all data is in labels.
| Label | Values | Meaning | | Label | Values | Meaning |
|---|---|---| |---|---|---|
| `version` | string | Script version (e.g. `25.30.0250400123`) | | `version` | string | Script version (e.g. `25.30.0250400123`) |
| `mode` | `live` / `no-runtime` / `no-hw` / `hw-only` | Operating mode (see below) | | `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 | | `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) | | `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 | | `sysfs_only` | `true` / `false` | `--sysfs-only` mode: only the kernel's own sysfs report was used, not independent detection |
@@ -90,16 +90,13 @@ 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 entirely when none of `kernel_release`, `kernel_arch`, or Absent in offline mode when neither `uname -r` nor `uname -m` is available.
`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`; emitted only in live mode | | `kernel_release` | string | Output of `uname -r` (live mode only) |
| `kernel_arch` | string | Output of `uname -m`; emitted only in live mode | | `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.); absent when VMM detection did not run (e.g. `--no-hw`) | | `hypervisor_host` | `true` / `false` | Whether this machine is detected as a hypervisor host (running KVM, Xen, VMware, etc.) |
**Example:** **Example:**
``` ```
@@ -117,47 +114,26 @@ 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 or when `--arch-prefix` is set (host CPU info is suppressed to avoid is used.
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. `GenuineIntel`, `AuthenticAMD`, `HygonGenuine`, `ARM`) | | `vendor` | string | CPU vendor (e.g. `Intel`, `AuthenticAMD`) |
| `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`) | | `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/Hygon | | `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 |
ARM-only labels (emitted when `arch="arm"`): **Example:**
| 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="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 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
```
**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:**
@@ -364,28 +340,16 @@ smc_vulnerability_status == 1
## Caveats and edge cases ## Caveats and edge cases
**No-runtime mode (`--no-runtime`)** **Offline mode (`--kernel`)**
`smc_system_info` will have no `kernel_release` or `kernel_arch` labels (those `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). come from `uname`, which reports the running kernel, not the inspected one).
`mode="no-runtime"` in `smc_build_info` signals this. No-runtime mode is `mode="offline"` in `smc_build_info` signals this. Offline mode is primarily
primarily useful for pre-deployment auditing, not fleet runtime monitoring. useful for pre-deployment auditing, not fleet runtime monitoring.
**No-hardware mode (`--no-hw`)** **`--no-hw`**
`smc_cpu_info` is not emitted. CPU and microcode labels are absent from all `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, 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.
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`)**
Only hardware detection is performed; CVE checks are skipped. `smc_cpu_info`
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.
**`--sysfs-only`** **`--sysfs-only`**
The script trusts the kernel's sysfs report (`/sys/devices/system/cpu/vulnerabilities/`) The script trusts the kernel's sysfs report (`/sys/devices/system/cpu/vulnerabilities/`)

View File

@@ -24,9 +24,6 @@ show_usage() {
can be used multiple times (e.g. --variant 3a --variant l1tf). For a list use 'help'. can be used multiple times (e.g. --variant 3a --variant l1tf). For a list use 'help'.
--cve CVE specify which CVE you'd like to check, by default all supported CVEs are checked --cve CVE specify which CVE you'd like to check, by default all supported CVEs are checked
can be used multiple times (e.g. --cve CVE-2017-5753 --cve CVE-2020-0543) can be used multiple times (e.g. --cve CVE-2017-5753 --cve CVE-2020-0543)
--errata NUMBER specify a vendor-numbered erratum (e.g. ARM64 erratum 1530923) that has no CVE
assigned. Maps the erratum to the corresponding check. For a list use 'help'.
Can be used multiple times (e.g. --errata 1530923 --errata 3194386).
Check scope: Check scope:
--no-sysfs don't use the /sys interface even if present [Linux] --no-sysfs don't use the /sys interface even if present [Linux]
@@ -128,13 +125,6 @@ opt_vmm=-1
opt_allow_msr_write=0 opt_allow_msr_write=0
opt_cpu=0 opt_cpu=0
opt_explain=0 opt_explain=0
# Canonical run mode, set at the end of option parsing.
# Values: live, no-runtime, no-hw, hw-only
g_mode='live'
# Return 0 (true) if runtime state is accessible (procfs, sysfs, dmesg, debugfs).
# True in live and hw-only modes; false in no-runtime and no-hw modes.
has_runtime() { [ "$g_mode" = live ] || [ "$g_mode" = hw-only ]; }
opt_paranoid=0 opt_paranoid=0
opt_extra=0 opt_extra=0
opt_mock=0 opt_mock=0
@@ -155,61 +145,40 @@ g_smc_system_info_line=''
g_smc_cpu_info_line='' 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|arch # Fields: cve_id|json_key_name|affected_var_suffix|complete_name_and_aliases
#
# The optional `arch` field gates whether the check is run at all, based on the
# host CPU architecture and the inspected kernel architecture. Values:
# x86 - only relevant when host CPU or inspected kernel is x86/amd64
# arm - only relevant when host CPU or inspected kernel is ARM/ARM64
# (empty) - always relevant (shared logic across architectures, e.g. Spectre V1-V4)
# The gate only applies to default "all CVEs" runs; explicit --cve/--variant/--errata
# selection bypasses it (if the user asks for it, they get it regardless of arch).
#
# Three 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-0001-NNNN: permanent placeholder for vendor-numbered errata that will never
# receive a CVE (e.g. ARM64 silicon errata tracked only by erratum ID).
# Selectable via --errata <number>.
# 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
CVE-2017-5754|MELTDOWN|variant3|Variant 3, Meltdown, rogue data cache load| CVE-2017-5754|MELTDOWN|variant3|Variant 3, Meltdown, rogue data cache load
CVE-2018-3640|VARIANT 3A|variant3a|Variant 3a, rogue system register read| CVE-2018-3640|VARIANT 3A|variant3a|Variant 3a, rogue system register read
CVE-2018-3639|VARIANT 4|variant4|Variant 4, speculative store bypass| CVE-2018-3639|VARIANT 4|variant4|Variant 4, speculative store bypass
CVE-2018-3615|L1TF SGX|variantl1tf_sgx|Foreshadow (SGX), L1 terminal fault|x86 CVE-2018-3615|L1TF SGX|variantl1tf_sgx|Foreshadow (SGX), L1 terminal fault
CVE-2018-3620|L1TF OS|variantl1tf|Foreshadow-NG (OS), L1 terminal fault|x86 CVE-2018-3620|L1TF OS|variantl1tf|Foreshadow-NG (OS), L1 terminal fault
CVE-2018-3646|L1TF VMM|variantl1tf|Foreshadow-NG (VMM), L1 terminal fault|x86 CVE-2018-3646|L1TF VMM|variantl1tf|Foreshadow-NG (VMM), L1 terminal fault
CVE-2018-12126|MSBDS|msbds|Fallout, microarchitectural store buffer data sampling (MSBDS)|x86 CVE-2018-12126|MSBDS|msbds|Fallout, microarchitectural store buffer data sampling (MSBDS)
CVE-2018-12130|MFBDS|mfbds|ZombieLoad, microarchitectural fill buffer data sampling (MFBDS)|x86 CVE-2018-12130|MFBDS|mfbds|ZombieLoad, microarchitectural fill buffer data sampling (MFBDS)
CVE-2018-12127|MLPDS|mlpds|RIDL, microarchitectural load port data sampling (MLPDS)|x86 CVE-2018-12127|MLPDS|mlpds|RIDL, microarchitectural load port data sampling (MLPDS)
CVE-2019-11091|MDSUM|mdsum|RIDL, microarchitectural data sampling uncacheable memory (MDSUM)|x86 CVE-2019-11091|MDSUM|mdsum|RIDL, microarchitectural data sampling uncacheable memory (MDSUM)
CVE-2019-11135|TAA|taa|ZombieLoad V2, TSX Asynchronous Abort (TAA)|x86 CVE-2019-11135|TAA|taa|ZombieLoad V2, TSX Asynchronous Abort (TAA)
CVE-2018-12207|ITLBMH|itlbmh|No eXcuses, iTLB Multihit, machine check exception on page size changes (MCEPSC)|x86 CVE-2018-12207|ITLBMH|itlbmh|No eXcuses, iTLB Multihit, machine check exception on page size changes (MCEPSC)
CVE-2020-0543|SRBDS|srbds|Special Register Buffer Data Sampling (SRBDS)|x86 CVE-2020-0543|SRBDS|srbds|Special Register Buffer Data Sampling (SRBDS)
CVE-2022-21123|SBDR|mmio|Shared Buffers Data Read (SBDR), MMIO Stale Data|x86 CVE-2022-21123|SBDR|mmio|Shared Buffers Data Read (SBDR), MMIO Stale Data
CVE-2022-21125|SBDS|mmio|Shared Buffers Data Sampling (SBDS), MMIO Stale Data|x86 CVE-2022-21125|SBDS|mmio|Shared Buffers Data Sampling (SBDS), MMIO Stale Data
CVE-2022-21166|DRPW|mmio|Device Register Partial Write (DRPW), MMIO Stale Data|x86 CVE-2022-21166|DRPW|mmio|Device Register Partial Write (DRPW), MMIO Stale Data
CVE-2023-20588|DIV0|div0|Division by Zero, AMD Zen1 speculative data leak|x86 CVE-2023-20588|DIV0|div0|Division by Zero, AMD Zen1 speculative data leak
CVE-2023-20593|ZENBLEED|zenbleed|Zenbleed, cross-process information leak|x86 CVE-2023-20593|ZENBLEED|zenbleed|Zenbleed, cross-process information leak
CVE-2022-40982|DOWNFALL|downfall|Downfall, gather data sampling (GDS)|x86 CVE-2022-40982|DOWNFALL|downfall|Downfall, gather data sampling (GDS)
CVE-2022-29900|RETBLEED AMD|retbleed|Retbleed, arbitrary speculative code execution with return instructions (AMD)|x86 CVE-2022-29900|RETBLEED AMD|retbleed|Retbleed, arbitrary speculative code execution with return instructions (AMD)
CVE-2022-29901|RETBLEED INTEL|retbleed|Retbleed, arbitrary speculative code execution with return instructions (Intel)|x86 CVE-2022-29901|RETBLEED INTEL|retbleed|Retbleed, arbitrary speculative code execution with return instructions (Intel)
CVE-2023-20569|INCEPTION|inception|Inception, return address security (RAS)|x86 CVE-2023-20569|INCEPTION|inception|Inception, return address security (RAS)
CVE-2023-23583|REPTAR|reptar|Reptar, redundant prefix issue|x86 CVE-2023-23583|REPTAR|reptar|Reptar, redundant prefix issue
CVE-2024-36350|TSA_SQ|tsa|Transient Scheduler Attack - Store Queue (TSA-SQ)|x86 CVE-2024-36350|TSA_SQ|tsa|Transient Scheduler Attack - Store Queue (TSA-SQ)
CVE-2024-36357|TSA_L1|tsa|Transient Scheduler Attack - L1 (TSA-L1)|x86 CVE-2024-36357|TSA_L1|tsa|Transient Scheduler Attack - L1 (TSA-L1)
CVE-2024-28956|ITS|its|Indirect Target Selection (ITS)|x86 CVE-2024-28956|ITS|its|Indirect Target Selection (ITS)
CVE-2025-40300|VMSCAPE|vmscape|VMScape, VM-exit stale branch prediction|x86 CVE-2025-40300|VMSCAPE|vmscape|VMScape, VM-exit stale branch prediction
CVE-2023-28746|RFDS|rfds|Register File Data Sampling (RFDS)|x86 CVE-2023-28746|RFDS|rfds|Register File Data Sampling (RFDS)
CVE-2024-45332|BPI|bpi|Branch Privilege Injection (BPI)|x86 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|x86
CVE-0001-0001|ARM SPEC AT|arm_spec_at|ARM64 errata 1165522/1319367/1319537/1530923, Speculative AT TLB corruption|arm
CVE-0001-0002|ARM SPEC UNPRIV LOAD|arm_spec_unpriv_load|ARM64 errata 2966298/3117295, Speculative unprivileged load|arm
CVE-0001-0003|ARM SSBS NOSYNC|arm_ssbs_nosync|ARM64 erratum 3194386, MSR SSBS not self-synchronizing|arm
' '
# Derive the supported CVE list from the registry # Derive the supported CVE list from the registry

View File

@@ -27,36 +27,6 @@ _infer_immune() { eval "[ -z \"\$affected_$1\" ] && affected_$1=1 || :"; }
# Use for: family-level catch-all fallbacks (Intel L1TF non-whitelist, itlbmh non-whitelist). # Use for: family-level catch-all fallbacks (Intel L1TF non-whitelist, itlbmh non-whitelist).
_infer_vuln() { eval "[ -z \"\$affected_$1\" ] && affected_$1=0 || :"; } _infer_vuln() { eval "[ -z \"\$affected_$1\" ] && affected_$1=0 || :"; }
# Return 0 (true) if a CVE's arch tag matches the current context (host CPU
# and/or target kernel), so the check is worth running. Untagged CVEs are
# always relevant.
# - In no-hw mode the host CPU is ignored: gate only on target kernel arch.
# - Otherwise a match on either the host CPU or the target kernel is enough
# (they normally agree in live mode; if they disagree, check_kernel_cpu_arch_mismatch
# has already forced no-hw, handled by the branch above).
# Args: $1=cve_id
# Callers: src/main.sh (CVE dispatch loop), check_cpu_vulnerabilities
_is_cve_relevant_arch() {
local arch
arch=$(_cve_registry_field "$1" 5)
# Untagged CVE: always relevant
[ -z "$arch" ] && return 0
case "$arch" in
x86)
[ "$g_mode" != no-hw ] && is_x86_cpu && return 0
is_x86_kernel && return 0
return 1
;;
arm)
[ "$g_mode" != no-hw ] && is_arm_cpu && return 0
is_arm_kernel && return 0
return 1
;;
esac
# Unknown tag value: don't gate (fail open)
return 0
}
# Return the cached affected_* status for a given CVE # Return the cached affected_* status for a given CVE
# Args: $1=cve_id # Args: $1=cve_id
# Returns: 0 if affected, 1 if not affected # Returns: 0 if affected, 1 if not affected
@@ -136,13 +106,8 @@ is_cpu_affected() {
affected_srbds='' affected_srbds=''
affected_mmio='' affected_mmio=''
affected_sls='' affected_sls=''
# ARM64 speculation-related errata (ARM Ltd, implementer 0x41); non-ARM systems are immune below. # DIV0, Zenbleed and Inception are all AMD specific, look for "is_amd" below:
affected_arm_spec_at=''
affected_arm_spec_unpriv_load=''
affected_arm_ssbs_nosync=''
# 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:
@@ -640,23 +605,13 @@ is_cpu_affected() {
fi fi
_set_immune variantl1tf _set_immune variantl1tf
# DIV0 (Zen1/Zen+) # DIV0 (Zen1 only)
# 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-flagged CPUs # bfff3c6692ce (v6.8): moved to init_amd_zen1(), unconditional for all Zen1
# The kernel's X86_FEATURE_ZEN1 covers family 0x17 models 0x00-0x2f and 0x50-0x5f, # All Zen1 CPUs are 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
@@ -861,85 +816,13 @@ is_cpu_affected() {
_infer_immune sls _infer_immune sls
fi fi
# ARM64 silicon errata (speculation/security-relevant, no CVE assignments).
# References: arch/arm64/Kconfig (ARM64_ERRATUM_*), arch/arm64/kernel/cpu_errata.c MIDR lists.
# Iterates per-core (impl, part, variant, revision) tuples. Implementers currently handled:
# 0x41 ARM Ltd; 0x51 Qualcomm (Kryo4xx Silver for erratum 1530923).
# Revision ranges mirror the kernel's MIDR_RANGE/MIDR_REV_RANGE/MIDR_REV macros. A variant
# 'v' and revision 'p' are packed as (v<<4)|p for range compares — equivalent to the kernel's
# layout (MIDR_VARIANT_SHIFT=20, MIDR_REVISION_MASK=0xf) under the same order semantics.
# Unknown variant/revision ⇒ treat as in range (whitelist principle, DEVELOPMENT.md rule 5).
if [ -n "$cpu_part_list" ]; then
i=0
for cpupart in $cpu_part_list; do
i=$((i + 1))
# shellcheck disable=SC2086
cpuimpl=$(echo $cpu_impl_list | awk '{print $'$i'}')
# shellcheck disable=SC2086
cpuvar=$(echo $cpu_variant_list | awk '{print $'$i'}')
# shellcheck disable=SC2086
cpurev=$(echo $cpu_revision_list | awk '{print $'$i'}')
packed=''
[ -n "$cpuvar" ] && [ -n "$cpurev" ] && packed=$(((cpuvar << 4) | cpurev))
# Speculative AT TLB corruption (errata 1165522, 1319367, 1319537, 1530923)
if [ "$cpuimpl" = 0x41 ]; then
if echo "$cpupart" | grep -q -w -e 0xd07 -e 0xd08; then
# Cortex-A57 (0xd07) / A72 (0xd08): all revisions
_set_vuln arm_spec_at
elif echo "$cpupart" | grep -q -w -e 0xd05 -e 0xd0b; then
# Cortex-A55 (0xd05) / A76 (0xd0b): r0p0..r2p0 (packed 0..32)
if [ -z "$packed" ] || [ "$packed" -le 32 ]; then
_set_vuln arm_spec_at
fi
fi
elif [ "$cpuimpl" = 0x51 ] && [ "$cpupart" = 0x805 ]; then
# Qualcomm Kryo4xx Silver: kernel matches MIDR_REV(var 0xd, rev 0xe) only — packed 0xde = 222
if [ -z "$packed" ] || [ "$packed" = 222 ]; then
_set_vuln arm_spec_at
fi
fi
# Speculative unprivileged load (errata 2966298 A520, 3117295 A510) — ARM Ltd only
if [ "$cpuimpl" = 0x41 ]; then
if [ "$cpupart" = 0xd46 ]; then
# Cortex-A510: all revisions
_set_vuln arm_spec_unpriv_load
elif [ "$cpupart" = 0xd80 ]; then
# Cortex-A520: r0p0..r0p1 (packed 0..1)
if [ -z "$packed" ] || [ "$packed" -le 1 ]; then
_set_vuln arm_spec_unpriv_load
fi
fi
fi
# MSR SSBS not self-synchronizing (erratum 3194386 + siblings) — ARM Ltd only, all revisions.
# A76/A77/A78/A78C/A710/A715/A720/A720AE/A725, X1/X1C/X2/X3/X4/X925, N1/N2/N3, V1/V2/V3/V3AE
if [ "$cpuimpl" = 0x41 ]; then
if echo "$cpupart" | grep -q -w \
-e 0xd0b -e 0xd0d -e 0xd41 -e 0xd4b \
-e 0xd47 -e 0xd4d -e 0xd81 -e 0xd89 -e 0xd87 \
-e 0xd44 -e 0xd4c -e 0xd48 -e 0xd4e -e 0xd82 -e 0xd85 \
-e 0xd0c -e 0xd49 -e 0xd8e \
-e 0xd40 -e 0xd4f -e 0xd84 -e 0xd83; then
_set_vuln arm_ssbs_nosync
fi
fi
done
fi
# Default everything else to immune (covers non-ARM, and ARM cores not in the affected lists)
_infer_immune arm_spec_at
_infer_immune arm_spec_unpriv_load
_infer_immune arm_ssbs_nosync
# shellcheck disable=SC2154 # shellcheck disable=SC2154
{ {
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 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: 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: 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"
pr_debug "is_cpu_affected: final results: arm_spec_at=$affected_arm_spec_at arm_spec_unpriv_load=$affected_arm_spec_unpriv_load arm_ssbs_nosync=$affected_arm_ssbs_nosync"
} }
affected_variantl1tf_sgx="$affected_variantl1tf" affected_variantl1tf_sgx="$affected_variantl1tf"
# even if we are affected to L1TF, if there's no SGX, we're not affected to the original foreshadow # even if we are affected to L1TF, if there's no SGX, we're not affected to the original foreshadow

View File

@@ -187,76 +187,58 @@ is_cpu_srbds_free() {
} }
# Check whether the CPU is architecturally immune to MMIO Stale Data
# Mirrors the kernel's arch_cap_mmio_immune() helper: ALL THREE ARCH_CAP bits must be set:
# ARCH_CAP_SBDR_SSDP_NO (bit 13), ARCH_CAP_FBSDP_NO (bit 14), ARCH_CAP_PSDP_NO (bit 15)
# Returns: 0 if immune, 1 otherwise
is_arch_cap_mmio_immune() {
[ "$cap_sbdr_ssdp_no" = 1 ] && [ "$cap_fbsdp_no" = 1 ] && [ "$cap_psdp_no" = 1 ]
}
# Check whether the CPU is known to be unaffected by MMIO Stale Data (CVE-2022-21123/21125/21166) # Check whether the CPU is known to be unaffected by MMIO Stale Data (CVE-2022-21123/21125/21166)
# Matches the kernel's NO_MMIO whitelist plus arch_cap_mmio_immune().
# Model inventory and kernel-commit history are documented in check_mmio_linux().
# Returns: 0 if MMIO-free, 1 if affected or unknown # Returns: 0 if MMIO-free, 1 if affected or unknown
is_cpu_mmio_free() { is_cpu_mmio_free() {
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c
#
# CPU affection logic from kernel (51802186158c, v5.19):
# Bug is set when: cpu_matches(blacklist, MMIO) AND NOT arch_cap_mmio_immune()
# arch_cap_mmio_immune() requires ALL THREE bits set:
# ARCH_CAP_FBSDP_NO (bit 14) AND ARCH_CAP_PSDP_NO (bit 15) AND ARCH_CAP_SBDR_SSDP_NO (bit 13)
#
# Intel Family 6 model blacklist (unchanged since v5.19):
# HASWELL_X (0x3F)
# BROADWELL_D (0x56), BROADWELL_X (0x4F)
# SKYLAKE_X (0x55), SKYLAKE_L (0x4E), SKYLAKE (0x5E)
# KABYLAKE_L (0x8E), KABYLAKE (0x9E)
# ICELAKE_L (0x7E), ICELAKE_D (0x6C), ICELAKE_X (0x6A)
# COMETLAKE (0xA5), COMETLAKE_L (0xA6)
# LAKEFIELD (0x8A)
# ROCKETLAKE (0xA7)
# ATOM_TREMONT (0x96), ATOM_TREMONT_D (0x86), ATOM_TREMONT_L (0x9C)
#
# Vendor scope: Intel only. Non-Intel CPUs are not affected.
parse_cpu_details parse_cpu_details
is_arch_cap_mmio_immune && return 0 # ARCH_CAP immunity: all three bits must be set
# Non-Intel x86 vendors the kernel unconditionally whitelists (AMD/Hygon all if [ "$cap_sbdr_ssdp_no" = 1 ] && [ "$cap_fbsdp_no" = 1 ] && [ "$cap_psdp_no" = 1 ]; then
# families; Centaur/Zhaoxin fam 7 only).
if is_amd || is_hygon; then
return 0 return 0
fi fi
if { [ "$cpu_vendor" = "CentaurHauls" ] || [ "$cpu_vendor" = "Shanghai" ]; } && [ "$cpu_family" = 7 ]; then if is_intel; then
return 0 if [ "$cpu_family" = 6 ]; then
fi if [ "$cpu_model" = "$INTEL_FAM6_HASWELL_X" ] ||
# Intel NO_MMIO whitelist [ "$cpu_model" = "$INTEL_FAM6_BROADWELL_D" ] ||
if is_intel && [ "$cpu_family" = 6 ]; then [ "$cpu_model" = "$INTEL_FAM6_BROADWELL_X" ] ||
if [ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE" ] || [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE_L" ] || [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE" ] || [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE_L" ] || [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] || [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] || [ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ]; then [ "$cpu_model" = "$INTEL_FAM6_ICELAKE_D" ] ||
return 0 [ "$cpu_model" = "$INTEL_FAM6_ICELAKE_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_LAKEFIELD" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_D" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_L" ]; then
return 1
fi
fi fi
fi fi
return 1
}
# Check whether the CPU's MMIO Stale Data status is unknown ("out of servicing period")
# Matches the kernel's X86_BUG_MMIO_UNKNOWN: Intel CPU not MMIO-free and not in the
# MMIO blacklist. The kernel reports "Unknown: No mitigations" for such CPUs.
# Callers: check_mmio_linux, check_mmio_bsd
# Returns: 0 if unknown, 1 if known (either affected or not affected)
is_cpu_mmio_unknown() {
parse_cpu_details
# Only Intel can reach the unknown bucket — other x86 vendors are whitelisted by vendor-id.
is_intel || return 1
is_cpu_mmio_free && return 1
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_HASWELL_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL_D" ] ||
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_D" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_LAKEFIELD" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_D" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_L" ]; then
return 1
fi
fi
return 0 return 0
} }

View File

@@ -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, fpdss, zenbleed, downfall, retbleed, inception, reptar, rfds, tsa, tsa-sq, tsa-l1, its, vmscape, bpi, sls, arm-spec-at, arm-spec-unpriv-load, arm-ssbs-nosync" 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"
exit 0 exit 0
;; ;;
1) 1)
@@ -245,10 +245,6 @@ 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
@@ -301,60 +297,12 @@ while [ -n "${1:-}" ]; do
opt_cve_list="$opt_cve_list CVE-0000-0001" opt_cve_list="$opt_cve_list CVE-0000-0001"
opt_cve_all=0 opt_cve_all=0
;; ;;
arm-spec-at)
opt_cve_list="$opt_cve_list CVE-0001-0001"
opt_cve_all=0
;;
arm-spec-unpriv-load)
opt_cve_list="$opt_cve_list CVE-0001-0002"
opt_cve_all=0
;;
arm-ssbs-nosync)
opt_cve_list="$opt_cve_list CVE-0001-0003"
opt_cve_all=0
;;
*) *)
echo "$0: error: invalid parameter '$2' for --variant, see --variant help for a list" >&2 echo "$0: error: invalid parameter '$2' for --variant, see --variant help for a list" >&2
exit 255 exit 255
;; ;;
esac esac
shift 2 shift 2
elif [ "$1" = "--errata" ]; then
# Vendor-numbered errata selector (currently ARM64). Maps an erratum number
# (e.g. 1530923) to the CVE-0001-NNNN check that covers it.
if [ -z "$2" ]; then
echo "$0: error: option --errata expects a parameter (an erratum number, e.g. 1530923, or 'help')" >&2
exit 255
fi
case "$2" in
help)
echo "The following erratum numbers are supported for --errata (can be used multiple times):"
echo " Speculative AT TLB corruption: 1165522, 1319367, 1319537, 1530923"
echo " Speculative unprivileged load: 2966298, 3117295"
echo " MSR SSBS not self-synchronizing: 3194386 (and siblings: 3312417, 3324334, 3324335,"
echo " 3324336, 3324338, 3324339, 3324341, 3324344, 3324346,"
echo " 3324347, 3324348, 3324349, 3456084, 3456091, 3456106,"
echo " 3456111)"
exit 0
;;
1165522 | 1319367 | 1319537 | 1530923)
opt_cve_list="$opt_cve_list CVE-0001-0001"
opt_cve_all=0
;;
2966298 | 3117295)
opt_cve_list="$opt_cve_list CVE-0001-0002"
opt_cve_all=0
;;
3194386 | 3312417 | 3324334 | 3324335 | 3324336 | 3324338 | 3324339 | 3324341 | 3324344 | 3324346 | 3324347 | 3324348 | 3324349 | 3456084 | 3456091 | 3456106 | 3456111)
opt_cve_list="$opt_cve_list CVE-0001-0003"
opt_cve_all=0
;;
*)
echo "$0: error: unsupported erratum number '$2' for --errata, see --errata help for a list" >&2
exit 255
;;
esac
shift 2
elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
show_header show_header
show_usage show_usage
@@ -396,16 +344,3 @@ if [ "$opt_runtime" = 0 ] && [ -z "$opt_kernel" ] && [ -z "$opt_config" ] && [ -
pr_warn "Option --no-runtime requires at least one of --kernel, --config, or --map" pr_warn "Option --no-runtime requires at least one of --kernel, --config, or --map"
exit 255 exit 255
fi fi
# Derive the canonical run mode from the option flags.
# Modes: live (default), no-runtime (--no-runtime), no-hw (--no-hw), hw-only (--hw-only)
# shellcheck disable=SC2034
if [ "$opt_hw_only" = 1 ]; then
g_mode='hw-only'
elif [ "$opt_no_hw" = 1 ]; then
g_mode='no-hw'
elif [ "$opt_runtime" = 0 ]; then
g_mode='no-runtime'
else
g_mode='live'
fi

View File

@@ -15,17 +15,15 @@ _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 boolean token # Convert a shell capability value to a JSON token
# Args: $1=value (1=true, 0=false, -1/empty=null, any other non-empty string=true) # Args: $1=value (1=true, 0=false, -1/empty=null, other string=quoted string)
# Prints: JSON token (true/false/null) # Prints: JSON token
# 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 'true' ;; *) printf '"%s"' "$(_json_escape "$1")" ;;
esac esac
} }
@@ -68,8 +66,17 @@ _json_bool() {
# Sets: g_json_meta # Sets: g_json_meta
# shellcheck disable=SC2034 # shellcheck disable=SC2034
_build_json_meta() { _build_json_meta() {
local timestamp local timestamp mode
timestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || echo "unknown") timestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || echo "unknown")
if [ "$opt_hw_only" = 1 ]; then
mode="hw-only"
elif [ "$opt_no_hw" = 1 ]; then
mode="no-hw"
elif [ "$opt_runtime" = 0 ]; then
mode="no-runtime"
else
mode="live"
fi
local run_as_root local run_as_root
if [ "$(id -u)" -eq 0 ]; then if [ "$(id -u)" -eq 0 ]; then
run_as_root='true' run_as_root='true'
@@ -80,7 +87,7 @@ _build_json_meta() {
"$(_json_str "$VERSION")" \ "$(_json_str "$VERSION")" \
"$(_json_str "$timestamp")" \ "$(_json_str "$timestamp")" \
"$(_json_str "$g_os")" \ "$(_json_str "$g_os")" \
"$g_mode" \ "$mode" \
"$run_as_root" \ "$run_as_root" \
"$(_json_bool "${g_bad_accuracy:-0}")" \ "$(_json_bool "${g_bad_accuracy:-0}")" \
"$(_json_bool "$opt_paranoid")" \ "$(_json_bool "$opt_paranoid")" \
@@ -93,7 +100,7 @@ _build_json_meta() {
# shellcheck disable=SC2034 # shellcheck disable=SC2034
_build_json_system() { _build_json_system() {
local kernel_release kernel_version kernel_arch smt_val local kernel_release kernel_version kernel_arch smt_val
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
kernel_release=$(uname -r) kernel_release=$(uname -r)
kernel_version=$(uname -v) kernel_version=$(uname -v)
kernel_arch=$(uname -m) kernel_arch=$(uname -m)
@@ -128,7 +135,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 sbpb_norm local cpuid_hex codename caps arch_sub arch_type
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
@@ -139,15 +146,6 @@ _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)
@@ -201,7 +199,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 "$sbpb_norm")" \ "$(_json_cap "${cap_sbpb:-}")" \
"$(_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}' \
@@ -406,7 +404,7 @@ _emit_prometheus() {
# shellcheck disable=SC2034 # shellcheck disable=SC2034
_build_prometheus_system_info() { _build_prometheus_system_info() {
local kernel_release kernel_arch hypervisor_host sys_labels local kernel_release kernel_arch hypervisor_host sys_labels
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
kernel_release=$(uname -r 2>/dev/null || true) kernel_release=$(uname -r 2>/dev/null || true)
kernel_arch=$(uname -m 2>/dev/null || true) kernel_arch=$(uname -m 2>/dev/null || true)
else else

View File

@@ -24,22 +24,13 @@ parse_cpu_details() {
if grep -qw avx512 "$g_procfs/cpuinfo" 2>/dev/null; then cap_avx512=1; fi if grep -qw avx512 "$g_procfs/cpuinfo" 2>/dev/null; then cap_avx512=1; fi
cpu_vendor=$(grep '^vendor_id' "$g_procfs/cpuinfo" | awk '{print $3}' | head -n1) cpu_vendor=$(grep '^vendor_id' "$g_procfs/cpuinfo" | awk '{print $3}' | head -n1)
cpu_friendly_name=$(grep '^model name' "$g_procfs/cpuinfo" | cut -d: -f2- | head -n1 | sed -e 's/^ *//') cpu_friendly_name=$(grep '^model name' "$g_procfs/cpuinfo" | cut -d: -f2- | head -n1 | sed -e 's/^ *//')
# ARM-style cpuinfo: parse per-core implementer/part/arch/variant/revision lists # special case for ARM follows
# (big.LITTLE / heterogeneous systems have different values per core).
# cpu_variant_list and cpu_revision_list are consumed by ARM64 errata affection checks
# that need to match a specific revision range.
if grep -q 'CPU implementer' "$g_procfs/cpuinfo"; then
cpu_impl_list=$(awk '/CPU implementer/ {print $4}' "$g_procfs/cpuinfo")
cpu_part_list=$(awk '/CPU part/ {print $4}' "$g_procfs/cpuinfo")
cpu_arch_list=$(awk '/CPU architecture/ {print $3}' "$g_procfs/cpuinfo")
cpu_variant_list=$(awk '/CPU variant/ {print $4}' "$g_procfs/cpuinfo")
cpu_revision_list=$(awk '/CPU revision/ {print $4}' "$g_procfs/cpuinfo")
fi
# Map first-seen implementer to cpu_vendor; note that heterogeneous systems
# (e.g. DynamIQ with ARM+Kryo cores) would all map to one vendor here, but
# per-core vendor decisions are made via cpu_impl_list where needed.
if grep -qi 'CPU implementer[[:space:]]*:[[:space:]]*0x41' "$g_procfs/cpuinfo"; then if grep -qi 'CPU implementer[[:space:]]*:[[:space:]]*0x41' "$g_procfs/cpuinfo"; then
cpu_vendor='ARM' cpu_vendor='ARM'
# some devices (phones or other) have several ARMs and as such different part numbers,
# an example is "bigLITTLE", so we need to store the whole list, this is needed for is_cpu_affected
cpu_part_list=$(awk '/CPU part/ {print $4}' "$g_procfs/cpuinfo")
cpu_arch_list=$(awk '/CPU architecture/ {print $3}' "$g_procfs/cpuinfo")
# take the first one to fill the friendly name, do NOT quote the vars below # take the first one to fill the friendly name, do NOT quote the vars below
# shellcheck disable=SC2086 # shellcheck disable=SC2086
arch=$(echo $cpu_arch_list | awk '{ print $1 }') arch=$(echo $cpu_arch_list | awk '{ print $1 }')

View File

@@ -1,120 +0,0 @@
# vim: set ts=4 sw=4 sts=4 et:
###############################
# Kernel architecture detection helpers.
# Detects the target kernel's architecture regardless of the host system,
# enabling correct behavior in offline cross-inspection (e.g. x86 host
# analyzing an ARM kernel image or System.map).
# Global cache; populated by _detect_kernel_arch on first call.
# Values: 'arm', 'x86', 'unknown'
g_kernel_arch=''
# Internal: populate g_kernel_arch using all available information sources,
# in order from most to least reliable.
_detect_kernel_arch() {
# Return immediately if already detected
[ -n "$g_kernel_arch" ] && return 0
# arm64_sys_ is the ARM64 syscall table symbol prefix; present in any
# ARM64 System.map (or /proc/kallsyms) and in the kernel image itself.
# sys_call_table + vector_swi is the ARM (32-bit) equivalent.
if [ -n "$opt_map" ]; then
if grep -q 'arm64_sys_' "$opt_map" 2>/dev/null; then
g_kernel_arch='arm'
return 0
fi
if grep -q ' vector_swi$' "$opt_map" 2>/dev/null; then
g_kernel_arch='arm'
return 0
fi
fi
if [ -n "$g_kernel" ]; then
if grep -q 'arm64_sys_' "$g_kernel" 2>/dev/null; then
g_kernel_arch='arm'
return 0
fi
fi
# Kconfig is definitive when available
if [ -n "$opt_config" ]; then
if grep -qE '^CONFIG_(ARM64|ARM)=y' "$opt_config" 2>/dev/null; then
g_kernel_arch='arm'
return 0
fi
if grep -qE '^CONFIG_X86(_64)?=y' "$opt_config" 2>/dev/null; then
g_kernel_arch='x86'
return 0
fi
fi
# Cross-compilation prefix as a last resort (e.g. --arch-prefix aarch64-linux-gnu-)
case "${opt_arch_prefix:-}" in
aarch64-* | arm64-* | arm-* | armv*-)
g_kernel_arch='arm'
return 0
;;
x86_64-* | i686-* | i?86-*)
g_kernel_arch='x86'
return 0
;;
esac
# Last resort: if no artifacts identified the arch, assume the target
# kernel matches the host CPU. This covers live mode when no kernel
# image, config, or System.map is available.
if is_x86_cpu; then
g_kernel_arch='x86'
return 0
fi
if is_arm_cpu; then
g_kernel_arch='arm'
return 0
fi
g_kernel_arch='unknown'
return 0
}
# Return 0 (true) if the target kernel is ARM (32 or 64-bit), 1 otherwise.
is_arm_kernel() {
_detect_kernel_arch
[ "$g_kernel_arch" = 'arm' ]
}
# Return 0 (true) if the target kernel is x86/x86_64, 1 otherwise.
is_x86_kernel() {
_detect_kernel_arch
[ "$g_kernel_arch" = 'x86' ]
}
# Compare the target kernel's architecture against the host CPU.
# If they differ, hardware reads (CPUID, MSR, sysfs) would reflect the host,
# not the target kernel — force no-hw mode to avoid misleading results.
# Sets: g_mode (when mismatch detected)
# Callers: src/main.sh (after check_kernel_info, before check_cpu)
check_kernel_cpu_arch_mismatch() {
local host_arch
_detect_kernel_arch
host_arch='unknown'
if is_x86_cpu; then
host_arch='x86'
elif is_arm_cpu; then
host_arch='arm'
fi
# Unsupported CPU architecture (MIPS, RISC-V, PowerPC, ...): force no-hw
# since we have no hardware-level checks for these platforms
if [ "$host_arch" = 'unknown' ]; then
pr_warn "Unsupported CPU architecture (vendor: $cpu_vendor), forcing no-hw mode"
g_mode='no-hw'
return 0
fi
# If kernel arch is unknown, we can't tell if there's a mismatch
[ "$g_kernel_arch" = 'unknown' ] && return 0
[ "$host_arch" = "$g_kernel_arch" ] && return 0
pr_warn "Target kernel architecture ($g_kernel_arch) differs from host CPU ($host_arch), forcing no-hw mode"
g_mode='no-hw'
}

View File

@@ -18,7 +18,7 @@ if [ "$g_os" = Darwin ] || [ "$g_os" = VMkernel ]; then
fi fi
# check for mode selection inconsistency # check for mode selection inconsistency
if [ "$g_mode" = hw-only ]; then if [ "$opt_hw_only" = 1 ]; then
if [ "$opt_cve_all" = 0 ]; then if [ "$opt_cve_all" = 0 ]; then
show_usage show_usage
echo "$0: error: incompatible modes specified, --hw-only vs --variant" >&2 echo "$0: error: incompatible modes specified, --hw-only vs --variant" >&2
@@ -89,7 +89,7 @@ if [ "$opt_cpu" != all ] && [ "$opt_cpu" -gt "$g_max_core_id" ]; then
exit 255 exit 255
fi fi
if has_runtime; then if [ "$opt_runtime" = 1 ]; then
pr_info "Checking for vulnerabilities on current system" pr_info "Checking for vulnerabilities on current system"
# try to find the image of the current running kernel # try to find the image of the current running kernel
@@ -226,7 +226,7 @@ if [ -e "$opt_kernel" ]; then
if ! command -v "${opt_arch_prefix}readelf" >/dev/null 2>&1; then if ! command -v "${opt_arch_prefix}readelf" >/dev/null 2>&1; then
pr_debug "readelf not found" pr_debug "readelf not found"
g_kernel_err="missing '${opt_arch_prefix}readelf' tool, please install it, usually it's in the 'binutils' package" g_kernel_err="missing '${opt_arch_prefix}readelf' tool, please install it, usually it's in the 'binutils' package"
elif [ "$opt_sysfs_only" = 1 ] || [ "$g_mode" = hw-only ]; then elif [ "$opt_sysfs_only" = 1 ] || [ "$opt_hw_only" = 1 ]; then
g_kernel_err='kernel image decompression skipped' g_kernel_err='kernel image decompression skipped'
else else
extract_kernel "$opt_kernel" extract_kernel "$opt_kernel"
@@ -251,7 +251,7 @@ else
fi fi
if [ -n "$g_kernel_version" ]; then if [ -n "$g_kernel_version" ]; then
# in live mode, check if the img we found is the correct one # in live mode, check if the img we found is the correct one
if has_runtime; then if [ "$opt_runtime" = 1 ]; then
pr_verbose "Kernel image is \033[35m$g_kernel_version" pr_verbose "Kernel image is \033[35m$g_kernel_version"
if ! echo "$g_kernel_version" | grep -qF "$(uname -r)"; then if ! echo "$g_kernel_version" | grep -qF "$(uname -r)"; then
pr_warn "Possible discrepancy between your running kernel '$(uname -r)' and the image '$g_kernel_version' we found ($opt_kernel), results might be incorrect" pr_warn "Possible discrepancy between your running kernel '$(uname -r)' and the image '$g_kernel_version' we found ($opt_kernel), results might be incorrect"
@@ -283,7 +283,7 @@ sys_interface_check() {
msg='' msg=''
ret_sys_interface_check_fullmsg='' ret_sys_interface_check_fullmsg=''
if has_runtime && [ "$opt_no_sysfs" = 0 ] && [ -r "$file" ]; then if [ "$opt_runtime" = 1 ] && [ "$opt_no_sysfs" = 0 ] && [ -r "$file" ]; then
: :
else else
g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_SYSFS_$(basename "$file")_RET=1") g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_SYSFS_$(basename "$file")_RET=1")
@@ -352,7 +352,7 @@ sys_interface_check() {
check_kernel_info() { check_kernel_info() {
local config_display local config_display
pr_info "\033[1;34mKernel information\033[0m" pr_info "\033[1;34mKernel information\033[0m"
if has_runtime; then if [ "$opt_runtime" = 1 ]; then
pr_info "* Kernel is \033[35m$g_os $(uname -r) $(uname -v) $(uname -m)\033[0m" pr_info "* Kernel is \033[35m$g_os $(uname -r) $(uname -v) $(uname -m)\033[0m"
elif [ -n "$g_kernel_version" ]; then elif [ -n "$g_kernel_version" ]; then
pr_info "* Kernel is \033[35m$g_kernel_version\033[0m" pr_info "* Kernel is \033[35m$g_kernel_version\033[0m"
@@ -456,7 +456,7 @@ check_cpu() {
ret=invalid ret=invalid
pstatus yellow NO "unknown CPU" pstatus yellow NO "unknown CPU"
fi fi
if [ -z "$cap_ibrs" ] && [ $ret = $READ_CPUID_RET_ERR ] && has_runtime; then if [ -z "$cap_ibrs" ] && [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw ibrs; then if grep ^flags "$g_procfs/cpuinfo" | grep -qw ibrs; then
cap_ibrs='IBRS (cpuinfo)' cap_ibrs='IBRS (cpuinfo)'
@@ -533,7 +533,7 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then if [ $ret = $READ_CPUID_RET_OK ]; then
cap_ibpb='IBPB_SUPPORT' cap_ibpb='IBPB_SUPPORT'
pstatus green YES "IBPB_SUPPORT feature bit" pstatus green YES "IBPB_SUPPORT feature bit"
elif [ $ret = $READ_CPUID_RET_ERR ] && has_runtime && grep ^flags "$g_procfs/cpuinfo" | grep -qw ibpb; then elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw ibpb; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
cap_ibpb='IBPB (cpuinfo)' cap_ibpb='IBPB (cpuinfo)'
pstatus green YES "ibpb flag in $g_procfs/cpuinfo" pstatus green YES "ibpb flag in $g_procfs/cpuinfo"
@@ -604,7 +604,7 @@ check_cpu() {
ret=invalid ret=invalid
pstatus yellow UNKNOWN "unknown CPU" pstatus yellow UNKNOWN "unknown CPU"
fi fi
if [ -z "$cap_stibp" ] && [ $ret = $READ_CPUID_RET_ERR ] && has_runtime; then if [ -z "$cap_stibp" ] && [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw stibp; then if grep ^flags "$g_procfs/cpuinfo" | grep -qw stibp; then
cap_stibp='STIBP (cpuinfo)' cap_stibp='STIBP (cpuinfo)'
@@ -676,7 +676,7 @@ check_cpu() {
fi fi
fi fi
if [ -z "$cap_ssbd" ] && [ "$ret24" = $READ_CPUID_RET_ERR ] && [ "$ret25" = $READ_CPUID_RET_ERR ] && has_runtime; then if [ -z "$cap_ssbd" ] && [ "$ret24" = $READ_CPUID_RET_ERR ] && [ "$ret25" = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw ssbd; then if grep ^flags "$g_procfs/cpuinfo" | grep -qw ssbd; then
cap_ssbd='SSBD (cpuinfo)' cap_ssbd='SSBD (cpuinfo)'
@@ -740,7 +740,7 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then if [ $ret = $READ_CPUID_RET_OK ]; then
pstatus green YES "L1D flush feature bit" pstatus green YES "L1D flush feature bit"
cap_l1df=1 cap_l1df=1
elif [ $ret = $READ_CPUID_RET_ERR ] && has_runtime && grep ^flags "$g_procfs/cpuinfo" | grep -qw flush_l1d; then elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw flush_l1d; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
pstatus green YES "flush_l1d flag in $g_procfs/cpuinfo" pstatus green YES "flush_l1d flag in $g_procfs/cpuinfo"
cap_l1df=1 cap_l1df=1
@@ -760,7 +760,7 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then if [ $ret = $READ_CPUID_RET_OK ]; then
cap_md_clear=1 cap_md_clear=1
pstatus green YES "MD_CLEAR feature bit" pstatus green YES "MD_CLEAR feature bit"
elif [ $ret = $READ_CPUID_RET_ERR ] && has_runtime && grep ^flags "$g_procfs/cpuinfo" | grep -qw md_clear; then elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw md_clear; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
cap_md_clear=1 cap_md_clear=1
pstatus green YES "md_clear flag in $g_procfs/cpuinfo" pstatus green YES "md_clear flag in $g_procfs/cpuinfo"
@@ -830,7 +830,7 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then if [ $ret = $READ_CPUID_RET_OK ]; then
pstatus green YES pstatus green YES
cap_arch_capabilities=1 cap_arch_capabilities=1
elif [ $ret = $READ_CPUID_RET_ERR ] && has_runtime && grep ^flags "$g_procfs/cpuinfo" | grep -qw arch_capabilities; then elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_runtime" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw arch_capabilities; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo # CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
pstatus green YES "arch_capabilities flag in $g_procfs/cpuinfo" pstatus green YES "arch_capabilities flag in $g_procfs/cpuinfo"
cap_arch_capabilities=1 cap_arch_capabilities=1
@@ -1093,7 +1093,7 @@ check_cpu() {
pr_info_nol " * CPU explicitly indicates not being affected by MMIO Stale Data (FBSDP_NO & PSDP_NO & SBDR_SSDP_NO): " pr_info_nol " * CPU explicitly indicates not being affected by MMIO Stale Data (FBSDP_NO & PSDP_NO & SBDR_SSDP_NO): "
if [ "$cap_sbdr_ssdp_no" = -1 ]; then if [ "$cap_sbdr_ssdp_no" = -1 ]; then
pstatus yellow UNKNOWN "couldn't read MSR" pstatus yellow UNKNOWN "couldn't read MSR"
elif is_arch_cap_mmio_immune; then elif [ "$cap_sbdr_ssdp_no" = 1 ] && [ "$cap_fbsdp_no" = 1 ] && [ "$cap_psdp_no" = 1 ]; then
pstatus green YES pstatus green YES
else else
pstatus yellow NO pstatus yellow NO
@@ -1367,19 +1367,11 @@ check_cpu() {
fi fi
} }
# Display per-CVE CPU vulnerability status based on CPU model/family. # Display per-CVE CPU vulnerability status based on CPU model/family
# Mirrors the main dispatch gate: under a default "all CVEs" run, skip CVEs
# whose arch tag doesn't match this system. Explicit selection via
# --cve/--variant/--errata bypasses the gate.
check_cpu_vulnerabilities() { check_cpu_vulnerabilities() {
local cve local cve
pr_info "* CPU vulnerability to the speculative execution attack variants" pr_info "* CPU vulnerability to the speculative execution attack variants"
for cve in $g_supported_cve_list; do for cve in $g_supported_cve_list; do
if [ "$opt_cve_all" = 1 ]; then
_is_cve_relevant_arch "$cve" || continue
elif ! echo "$opt_cve_list" | grep -qw "$cve"; then
continue
fi
pr_info_nol " * Affected by $cve ($(cve2name "$cve")): " pr_info_nol " * Affected by $cve ($(cve2name "$cve")): "
if is_cpu_affected "$cve"; then if is_cpu_affected "$cve"; then
pstatus yellow YES pstatus yellow YES

View File

@@ -14,7 +14,7 @@ fi
pr_info pr_info
if [ "$g_mode" != no-hw ] && [ -z "$opt_arch_prefix" ]; then if [ "$opt_no_hw" = 0 ] && [ -z "$opt_arch_prefix" ]; then
pr_info "\033[1;34mHardware check\033[0m" pr_info "\033[1;34mHardware check\033[0m"
check_cpu check_cpu
check_cpu_vulnerabilities check_cpu_vulnerabilities
@@ -24,7 +24,7 @@ fi
# Build JSON system/cpu/microcode sections (after check_cpu has populated cap_* vars and VMM detection) # Build JSON system/cpu/microcode sections (after check_cpu has populated cap_* vars and VMM detection)
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "json" ]; then if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "json" ]; then
_build_json_system _build_json_system
if [ "$g_mode" != no-hw ] && [ -z "$opt_arch_prefix" ]; then if [ "$opt_no_hw" = 0 ] && [ -z "$opt_arch_prefix" ]; then
_build_json_cpu _build_json_cpu
_build_json_cpu_microcode _build_json_cpu_microcode
fi fi
@@ -33,31 +33,18 @@ fi
# Build Prometheus info metric lines (same timing requirement as JSON builders above) # Build Prometheus info metric lines (same timing requirement as JSON builders above)
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then
_build_prometheus_system_info _build_prometheus_system_info
if [ "$g_mode" != no-hw ] && [ -z "$opt_arch_prefix" ]; then if [ "$opt_no_hw" = 0 ] && [ -z "$opt_arch_prefix" ]; then
_build_prometheus_cpu_info _build_prometheus_cpu_info
fi fi
fi fi
# now run the checks the user asked for (hw-only mode skips CVE checks) # now run the checks the user asked for
if [ "$g_mode" = hw-only ]; then for cve in $g_supported_cve_list; do
pr_info "Hardware-only mode, skipping vulnerability checks" if [ "$opt_cve_all" = 1 ] || echo "$opt_cve_list" | grep -qw "$cve"; then
else
for cve in $g_supported_cve_list; do
# In a default "all CVEs" run, skip checks whose arch tag doesn't match
# the host CPU or the inspected kernel. Explicit --cve/--variant/--errata
# selection bypasses the gate.
if [ "$opt_cve_all" = 1 ]; then
if ! _is_cve_relevant_arch "$cve"; then
pr_debug "main: skipping $cve (arch tag not relevant)"
continue
fi
elif ! echo "$opt_cve_list" | grep -qw "$cve"; then
continue
fi
check_"$(echo "$cve" | tr - _)" check_"$(echo "$cve" | tr - _)"
pr_info pr_info
done fi
fi # g_mode != hw-only done
if [ -n "$g_final_summary" ]; then if [ -n "$g_final_summary" ]; then
pr_info "> \033[46m\033[30mSUMMARY:\033[0m$g_final_summary" pr_info "> \033[46m\033[30mSUMMARY:\033[0m$g_final_summary"
@@ -184,7 +171,15 @@ fi
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then
prom_run_as_root='false' prom_run_as_root='false'
[ "$(id -u)" -eq 0 ] && prom_run_as_root='true' [ "$(id -u)" -eq 0 ] && prom_run_as_root='true'
prom_mode="$g_mode" if [ "$opt_hw_only" = 1 ]; then
prom_mode='hw-only'
elif [ "$opt_no_hw" = 1 ]; then
prom_mode='no-hw'
elif [ "$opt_runtime" = 0 ]; then
prom_mode='no-runtime'
else
prom_mode='live'
fi
prom_paranoid='false' prom_paranoid='false'
[ "$opt_paranoid" = 1 ] && prom_paranoid='true' [ "$opt_paranoid" = 1 ] && prom_paranoid='true'
prom_sysfs_only='false' prom_sysfs_only='false'

View File

@@ -3,7 +3,7 @@
check_mds_bsd() { check_mds_bsd() {
local kernel_md_clear kernel_smt_allowed kernel_mds_enabled kernel_mds_state local kernel_md_clear kernel_smt_allowed kernel_mds_enabled kernel_mds_state
pr_info_nol "* Kernel supports using MD_CLEAR mitigation: " pr_info_nol "* Kernel supports using MD_CLEAR mitigation: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if sysctl hw.mds_disable >/dev/null 2>&1; then if sysctl hw.mds_disable >/dev/null 2>&1; then
pstatus green YES pstatus green YES
kernel_md_clear=1 kernel_md_clear=1
@@ -76,7 +76,7 @@ check_mds_bsd() {
else else
if [ "$cap_md_clear" = 1 ]; then if [ "$cap_md_clear" = 1 ]; then
if [ "$kernel_md_clear" = 1 ]; then if [ "$kernel_md_clear" = 1 ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# mitigation must also be enabled # mitigation must also be enabled
if [ "$kernel_mds_enabled" -ge 1 ]; then if [ "$kernel_mds_enabled" -ge 1 ]; then
if [ "$opt_paranoid" != 1 ] || [ "$kernel_smt_allowed" = 0 ]; then if [ "$opt_paranoid" != 1 ] || [ "$kernel_smt_allowed" = 0 ]; then
@@ -95,7 +95,7 @@ check_mds_bsd() {
pvulnstatus "$cve" VULN "Your microcode supports mitigation, but your kernel doesn't, upgrade it to mitigate the vulnerability" pvulnstatus "$cve" VULN "Your microcode supports mitigation, but your kernel doesn't, upgrade it to mitigate the vulnerability"
fi fi
else else
if [ "$kernel_md_clear" = 1 ] && [ "$g_mode" = live ]; then if [ "$kernel_md_clear" = 1 ] && [ "$opt_runtime" = 1 ]; then
# no MD_CLEAR in microcode, but FreeBSD may still have software-only mitigation active # no MD_CLEAR in microcode, but FreeBSD may still have software-only mitigation active
case "$kernel_mds_state" in case "$kernel_mds_state" in
software*) software*)
@@ -138,7 +138,7 @@ check_mds_linux() {
if is_x86_kernel; then if is_x86_kernel; then
pr_info_nol "* Kernel supports using MD_CLEAR mitigation: " pr_info_nol "* Kernel supports using MD_CLEAR mitigation: "
kernel_md_clear_can_tell=1 kernel_md_clear_can_tell=1
if [ "$g_mode" = live ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw md_clear; then if [ "$opt_runtime" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw md_clear; then
kernel_md_clear="md_clear found in $g_procfs/cpuinfo" kernel_md_clear="md_clear found in $g_procfs/cpuinfo"
pstatus green YES "$kernel_md_clear" pstatus green YES "$kernel_md_clear"
fi fi
@@ -161,7 +161,7 @@ check_mds_linux() {
fi fi
fi fi
if [ "$g_mode" = live ] && [ "$sys_interface_available" = 1 ]; then if [ "$opt_runtime" = 1 ] && [ "$sys_interface_available" = 1 ]; then
pr_info_nol "* Kernel mitigation is enabled and active: " pr_info_nol "* Kernel mitigation is enabled and active: "
if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then
mds_mitigated=1 mds_mitigated=1
@@ -194,7 +194,7 @@ check_mds_linux() {
# compute mystatus and mymsg from our own logic # compute mystatus and mymsg from our own logic
if [ "$cap_md_clear" = 1 ]; then if [ "$cap_md_clear" = 1 ]; then
if [ -n "$kernel_md_clear" ]; then if [ -n "$kernel_md_clear" ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# mitigation must also be enabled # mitigation must also be enabled
if [ "$mds_mitigated" = 1 ]; then if [ "$mds_mitigated" = 1 ]; then
if [ "$opt_paranoid" != 1 ] || [ "$mds_smt_mitigated" = 1 ]; then if [ "$opt_paranoid" != 1 ] || [ "$mds_smt_mitigated" = 1 ]; then

View File

@@ -1,30 +1,16 @@
# vim: set ts=4 sw=4 sts=4 et: # vim: set ts=4 sw=4 sts=4 et:
# MMIO Stale Data (Processor MMIO Stale Data Vulnerabilities) - BSD mitigation check # MMIO Stale Data (Processor MMIO Stale Data Vulnerabilities) - BSD mitigation check
check_mmio_bsd() { check_mmio_bsd() {
# No BSD (FreeBSD, OpenBSD, NetBSD, DragonFlyBSD) has implemented an OS-level
# MMIO Stale Data mitigation. All four stopped at MDS/TAA. Microcode update is
# the only partial defense available, and without OS-level VERW invocation it
# cannot close the vulnerability.
local unk
unk="your CPU's MMIO Stale Data status is unknown (Intel never officially assessed this CPU, its servicing period has ended)"
if ! is_cpu_affected "$cve"; then if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected" pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
elif is_cpu_mmio_unknown; then
if [ "$opt_paranoid" = 1 ]; then
pvulnstatus "$cve" VULN "$unk, and no BSD mitigation exists"
explain "There is no known mitigation for this CPU model. Even with up-to-date microcode, BSD kernels do not invoke VERW for MMIO Stale Data clearing. Only a hardware replacement can fully address this."
else
pvulnstatus "$cve" UNK "$unk; no BSD mitigation exists in any case"
fi
else else
pvulnstatus "$cve" VULN "your CPU is affected and no BSD has implemented an MMIO Stale Data mitigation" pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
explain "No BSD kernel currently implements an MMIO Stale Data mitigation (which would require invoking VERW at context switches and VM-entries). Updating CPU microcode alone does not mitigate this vulnerability without OS cooperation."
fi fi
} }
# MMIO Stale Data (Processor MMIO Stale Data Vulnerabilities) - Linux mitigation check # MMIO Stale Data (Processor MMIO Stale Data Vulnerabilities) - Linux mitigation check
check_mmio_linux() { check_mmio_linux() {
local status sys_interface_available msg kernel_mmio kernel_mmio_can_tell mmio_mitigated mmio_smt_mitigated mystatus mymsg unk local status sys_interface_available msg kernel_mmio kernel_mmio_can_tell mmio_mitigated mmio_smt_mitigated mystatus mymsg
status=UNK status=UNK
sys_interface_available=0 sys_interface_available=0
msg='' msg=''
@@ -126,33 +112,9 @@ check_mmio_linux() {
# #
# No models have been added to or removed from the MMIO blacklist since v5.19. # No models have been added to or removed from the MMIO blacklist since v5.19.
# #
# 7df548840c49 (v6.0, NO_MMIO whitelist added, Pawan Gupta 2022-08-03):
# Intel Family 6:
# TIGERLAKE (0x8D), TIGERLAKE_L (0x8C)
# ALDERLAKE (0x97), ALDERLAKE_L (0x9A)
# ATOM_GOLDMONT (0x5C), ATOM_GOLDMONT_D (0x5F), ATOM_GOLDMONT_PLUS (0x7A)
# AMD: fam 0x0f-0x12 + X86_FAMILY_ANY (all families)
# Hygon: all families
# Centaur fam 7, Zhaoxin fam 7
#
# Kernel logic (v6.0+):
# if (!arch_cap_mmio_immune(ia32_cap)) {
# if (cpu_matches(cpu_vuln_blacklist, MMIO))
# setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
# else if (!cpu_matches(cpu_vuln_whitelist, NO_MMIO))
# setup_force_cpu_bug(X86_BUG_MMIO_UNKNOWN);
# }
# => Intel CPUs that are neither blacklisted nor whitelisted (e.g. Ivy Bridge,
# Haswell client, Broadwell client, Sandy Bridge, pre-Goldmont Atom, etc.) get
# X86_BUG_MMIO_UNKNOWN and report "Unknown: No mitigations" in sysfs. Intel
# never published an affected-processor evaluation for these models because
# their servicing period had already ended.
# => is_cpu_mmio_unknown() matches this set so the script can report UNK (or
# VULN under --paranoid) rather than the misleading "not affected" that
# a plain blacklist check would produce.
#
# immunity: ARCH_CAP_SBDR_SSDP_NO (bit 13) AND ARCH_CAP_FBSDP_NO (bit 14) AND ARCH_CAP_PSDP_NO (bit 15) # immunity: ARCH_CAP_SBDR_SSDP_NO (bit 13) AND ARCH_CAP_FBSDP_NO (bit 14) AND ARCH_CAP_PSDP_NO (bit 15)
# All three must be set. Checked via arch_cap_mmio_immune() in common.c. # All three must be set. Checked via arch_cap_mmio_immune() in common.c.
# Bug is set only when: cpu_matches(blacklist, MMIO) AND NOT arch_cap_mmio_immune().
# #
# microcode mitigation: ARCH_CAP_FB_CLEAR (bit 17) -- VERW clears fill buffers. # microcode mitigation: ARCH_CAP_FB_CLEAR (bit 17) -- VERW clears fill buffers.
# Alternative: MD_CLEAR CPUID + FLUSH_L1D CPUID when MDS_NO is not set (legacy path). # Alternative: MD_CLEAR CPUID + FLUSH_L1D CPUID when MDS_NO is not set (legacy path).
@@ -203,7 +165,7 @@ check_mmio_linux() {
pstatus yellow NO pstatus yellow NO
fi fi
if [ "$g_mode" = live ] && [ "$sys_interface_available" = 1 ]; then if [ "$opt_runtime" = 1 ] && [ "$sys_interface_available" = 1 ]; then
pr_info_nol "* Kernel mitigation is enabled and active: " pr_info_nol "* Kernel mitigation is enabled and active: "
if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then
mmio_mitigated=1 mmio_mitigated=1
@@ -231,23 +193,12 @@ check_mmio_linux() {
if ! is_cpu_affected "$cve"; then if ! is_cpu_affected "$cve"; then
# override status & msg in case CPU is not vulnerable after all # override status & msg in case CPU is not vulnerable after all
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected" pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
elif [ "$opt_sysfs_only" != 1 ] && is_cpu_mmio_unknown; then
# Bypass the normal sysfs reconciliation: sysfs reports "Unknown: No mitigations"
# only on v6.0-v6.15. On earlier and on v6.16+ kernels it wrongly says "Not affected"
# for these CPUs (which predate FB_CLEAR microcode and Intel's affected-processor list).
unk="your CPU's MMIO Stale Data status is unknown (Intel never officially assessed this CPU, its servicing period has ended)"
if [ "$opt_paranoid" = 1 ]; then
pvulnstatus "$cve" VULN "$unk, and no mitigation is available"
explain "There is no known mitigation for this CPU model. Intel ended its servicing period without evaluating whether it is affected by MMIO Stale Data vulnerabilities, so no FB_CLEAR-capable microcode was released. Consider replacing affected hardware."
else
pvulnstatus "$cve" UNK "$unk; no mitigation is available in any case"
fi
else else
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
# compute mystatus and mymsg from our own logic # compute mystatus and mymsg from our own logic
if [ "$cap_fb_clear" = 1 ]; then if [ "$cap_fb_clear" = 1 ]; then
if [ -n "$kernel_mmio" ]; then if [ -n "$kernel_mmio" ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# mitigation must also be enabled # mitigation must also be enabled
if [ "$mmio_mitigated" = 1 ]; then if [ "$mmio_mitigated" = 1 ]; then
if [ "$opt_paranoid" != 1 ] || [ "$mmio_smt_mitigated" = 1 ]; then if [ "$opt_paranoid" != 1 ] || [ "$mmio_smt_mitigated" = 1 ]; then

View File

@@ -1,78 +0,0 @@
# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-0001-0001, ARM SPEC AT, ARM64 errata 1165522/1319367/1319537/1530923, Speculative AT TLB corruption
check_CVE_0001_0001() {
check_cve 'CVE-0001-0001'
}
# On affected cores, a speculative address translation (AT) instruction issued from the hypervisor
# using an out-of-context translation regime may poison the TLB, causing a subsequent guest-context
# request to see an incorrect translation. Relevant mainly to KVM hosts. Kernel workaround:
# invalidate TLB state across world-switch for affected cores (ARM64_WORKAROUND_SPECULATIVE_AT).
# * Cortex-A76 r0p0..r2p0 erratum 1165522 CONFIG_ARM64_ERRATUM_1165522
# * Cortex-A72 all revs erratum 1319367 CONFIG_ARM64_ERRATUM_1319367
# * Cortex-A57 all revs erratum 1319537 CONFIG_ARM64_ERRATUM_1319367 (same kconfig)
# * Cortex-A55 r0p0..r2p0 erratum 1530923 CONFIG_ARM64_ERRATUM_1530923
# References:
# arch/arm64/Kconfig (ARM64_ERRATUM_{1165522,1319367,1530923})
# arch/arm64/kernel/cpu_errata.c (erratum_speculative_at_list, "ARM errata 1165522, 1319367, or 1530923")
# Cortex-A55 SDEN: https://developer.arm.com/documentation/SDEN-1301074/latest
check_CVE_0001_0001_linux() {
local cve kernel_mitigated config_found
cve='CVE-0001-0001'
kernel_mitigated=''
config_found=''
if [ "$opt_sysfs_only" != 1 ] && is_arm_kernel; then
# kconfig: any of the three erratum config options implies the workaround is compiled in
if [ -n "$opt_config" ]; then
for erratum in 1165522 1319367 1530923; do
if grep -q "^CONFIG_ARM64_ERRATUM_$erratum=y" "$opt_config"; then
config_found="${config_found:+$config_found, }$erratum"
fi
done
[ -n "$config_found" ] && kernel_mitigated="found CONFIG_ARM64_ERRATUM_$config_found=y in kernel config"
fi
# kernel image: look for the descriptor string the kernel prints at boot
if [ -z "$kernel_mitigated" ] && [ -n "$g_kernel" ]; then
if "${opt_arch_prefix}strings" "$g_kernel" 2>/dev/null | grep -qE 'ARM errata 1165522, 1319367'; then
kernel_mitigated="found erratum descriptor string in kernel image"
fi
fi
# live mode: dmesg prints the workaround once at boot
if [ -z "$kernel_mitigated" ] && [ "$g_mode" = live ]; then
if dmesg 2>/dev/null | grep -qE 'ARM errata 1165522, 1319367'; then
kernel_mitigated="erratum workaround reported as applied in dmesg"
fi
fi
pr_info_nol "* Kernel has the ARM64 Speculative-AT workaround compiled in: "
if [ -n "$kernel_mitigated" ]; then
pstatus green YES "$kernel_mitigated"
else
pstatus yellow NO
fi
fi
if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU is not affected by this erratum family"
elif [ "$opt_sysfs_only" = 1 ]; then
pvulnstatus "$cve" UNK "no sysfs interface exists for this erratum, own checks have been skipped (--sysfs-only)"
elif [ -n "$kernel_mitigated" ]; then
pvulnstatus "$cve" OK "your kernel includes the erratum workaround"
else
pvulnstatus "$cve" VULN "your CPU is affected by this erratum family and the kernel does not appear to include the workaround"
explain "Run a kernel built with CONFIG_ARM64_ERRATUM_1165522=y, CONFIG_ARM64_ERRATUM_1319367=y, and/or CONFIG_ARM64_ERRATUM_1530923=y (matching your CPU core). These options are 'default y' in mainline and enabled by most distro kernels. Refer to the ARM Software Developers Errata Notice for your core for full details."
fi
}
check_CVE_0001_0001_bsd() {
local cve
cve='CVE-0001-0001'
if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU is not affected by this erratum family"
else
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
fi
}

View File

@@ -1,75 +0,0 @@
# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-0001-0002, ARM SPEC UNPRIV LOAD, ARM64 errata 2966298/3117295, Speculative unprivileged load
check_CVE_0001_0002() {
check_cve 'CVE-0001-0002'
}
# On affected cores, a speculatively-executed unprivileged load from a page that is mapped as
# privileged can leak the loaded value into the cache hierarchy, allowing a Spectre-style
# cache side-channel to expose privileged kernel data to userspace. Kernel workaround:
# sandwich kernel-exit sequences with an additional speculation barrier/DSB so that
# speculative unprivileged loads cannot observe privileged state
# (ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD).
# * Cortex-A510 all revs erratum 3117295 CONFIG_ARM64_ERRATUM_3117295
# * Cortex-A520 r0p0..r0p1 erratum 2966298 CONFIG_ARM64_ERRATUM_2966298
# References:
# arch/arm64/Kconfig (ARM64_ERRATUM_{2966298,3117295})
# arch/arm64/kernel/cpu_errata.c (erratum_spec_unpriv_load_list, "ARM errata 2966298, 3117295")
# Cortex-A510 SDEN: https://developer.arm.com/documentation/SDEN-2397239/latest
check_CVE_0001_0002_linux() {
local cve kernel_mitigated config_found erratum
cve='CVE-0001-0002'
kernel_mitigated=''
config_found=''
if [ "$opt_sysfs_only" != 1 ] && is_arm_kernel; then
if [ -n "$opt_config" ]; then
for erratum in 2966298 3117295; do
if grep -q "^CONFIG_ARM64_ERRATUM_$erratum=y" "$opt_config"; then
config_found="${config_found:+$config_found, }$erratum"
fi
done
[ -n "$config_found" ] && kernel_mitigated="found CONFIG_ARM64_ERRATUM_$config_found=y in kernel config"
fi
if [ -z "$kernel_mitigated" ] && [ -n "$g_kernel" ]; then
if "${opt_arch_prefix}strings" "$g_kernel" 2>/dev/null | grep -qE 'ARM errata 2966298, 3117295'; then
kernel_mitigated="found erratum descriptor string in kernel image"
fi
fi
if [ -z "$kernel_mitigated" ] && [ "$g_mode" = live ]; then
if dmesg 2>/dev/null | grep -qE 'ARM errata 2966298, 3117295'; then
kernel_mitigated="erratum workaround reported as applied in dmesg"
fi
fi
pr_info_nol "* Kernel has the ARM64 Speculative-Unprivileged-Load workaround compiled in: "
if [ -n "$kernel_mitigated" ]; then
pstatus green YES "$kernel_mitigated"
else
pstatus yellow NO
fi
fi
if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU is not affected by this erratum family"
elif [ "$opt_sysfs_only" = 1 ]; then
pvulnstatus "$cve" UNK "no sysfs interface exists for this erratum, own checks have been skipped (--sysfs-only)"
elif [ -n "$kernel_mitigated" ]; then
pvulnstatus "$cve" OK "your kernel includes the erratum workaround"
else
pvulnstatus "$cve" VULN "your CPU is affected by this erratum family and the kernel does not appear to include the workaround"
explain "Run a kernel built with CONFIG_ARM64_ERRATUM_2966298=y (Cortex-A520) and/or CONFIG_ARM64_ERRATUM_3117295=y (Cortex-A510). These options are 'default y' in mainline and enabled by most distro kernels. Refer to the ARM Software Developers Errata Notice for your core for full details."
fi
}
check_CVE_0001_0002_bsd() {
local cve
cve='CVE-0001-0002'
if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU is not affected by this erratum family"
else
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
fi
}

View File

@@ -1,70 +0,0 @@
# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-0001-0003, ARM SSBS NOSYNC, ARM64 erratum 3194386, MSR SSBS not self-synchronizing
check_CVE_0001_0003() {
check_cve 'CVE-0001-0003'
}
# On affected cores, the "MSR SSBS, #x" instruction is not self-synchronizing, so subsequent
# speculative instructions may execute without observing the new SSBS state. This can permit
# unintended speculative store bypass (Spectre V4 / CVE-2018-3639) even when software thinks
# the mitigation is in effect. Kernel workaround (ARM64_WORKAROUND_SPECULATIVE_SSBS):
# - place a Speculation Barrier (SB) or ISB after every kernel-side SSBS change
# - hide SSBS from userspace hwcaps and EL0 reads of ID_AA64PFR1_EL1 so that userspace
# routes SSB mitigation changes through the prctl(PR_SET_SPECULATION_CTRL) path
# Affected cores (via ARM64_ERRATUM_3194386, with individual sub-errata numbers):
# Cortex-A76/A77/A78/A78C/A710/A715/A720/A720AE/A725, X1/X1C/X2/X3/X4/X925,
# Neoverse-N1/N2/N3, Neoverse-V1/V2/V3/V3AE
# References:
# arch/arm64/Kconfig (ARM64_ERRATUM_3194386)
# arch/arm64/kernel/cpu_errata.c (erratum_spec_ssbs_list, "SSBS not fully self-synchronizing")
check_CVE_0001_0003_linux() {
local cve kernel_mitigated
cve='CVE-0001-0003'
kernel_mitigated=''
if [ "$opt_sysfs_only" != 1 ] && is_arm_kernel; then
if [ -n "$opt_config" ] && grep -q '^CONFIG_ARM64_ERRATUM_3194386=y' "$opt_config"; then
kernel_mitigated="found CONFIG_ARM64_ERRATUM_3194386=y in kernel config"
fi
if [ -z "$kernel_mitigated" ] && [ -n "$g_kernel" ]; then
if "${opt_arch_prefix}strings" "$g_kernel" 2>/dev/null | grep -qE 'SSBS not fully self-synchronizing'; then
kernel_mitigated="found erratum descriptor string in kernel image"
fi
fi
if [ -z "$kernel_mitigated" ] && [ "$g_mode" = live ]; then
if dmesg 2>/dev/null | grep -qE 'SSBS not fully self-synchronizing'; then
kernel_mitigated="erratum workaround reported as applied in dmesg"
fi
fi
pr_info_nol "* Kernel has the ARM64 SSBS self-sync workaround compiled in: "
if [ -n "$kernel_mitigated" ]; then
pstatus green YES "$kernel_mitigated"
else
pstatus yellow NO
fi
fi
if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU is not affected by this erratum"
elif [ "$opt_sysfs_only" = 1 ]; then
pvulnstatus "$cve" UNK "no sysfs interface exists for this erratum, own checks have been skipped (--sysfs-only)"
elif [ -n "$kernel_mitigated" ]; then
pvulnstatus "$cve" OK "your kernel includes the erratum workaround"
else
pvulnstatus "$cve" VULN "your CPU is affected by this erratum and the kernel does not appear to include the workaround; Spectre V4 (CVE-2018-3639) mitigation may be unreliable on this system"
explain "Run a kernel built with CONFIG_ARM64_ERRATUM_3194386=y. This option is 'default y' in mainline and enabled by most distro kernels. Without it, the Spectre V4 / speculative-store-bypass mitigation advertised by SSBS is not reliably applied. Userspace should use prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, ...) to request the mitigation rather than rely on the SSBS hwcap."
fi
}
check_CVE_0001_0003_bsd() {
local cve
cve='CVE-0001-0003'
if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU is not affected by this erratum"
else
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
fi
}

View File

@@ -269,7 +269,7 @@ check_CVE_2017_5715_linux() {
g_ibpb_supported='' g_ibpb_supported=''
g_ibpb_enabled='' g_ibpb_enabled=''
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# in live mode, we can check for the ibrs_enabled file in debugfs # in live mode, we can check for the ibrs_enabled file in debugfs
# all versions of the patches have it (NOT the case of IBPB or KPTI) # all versions of the patches have it (NOT the case of IBPB or KPTI)
g_ibrs_can_tell=1 g_ibrs_can_tell=1
@@ -420,7 +420,7 @@ check_CVE_2017_5715_linux() {
fi fi
pr_info_nol " * IBRS enabled and active: " pr_info_nol " * IBRS enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ "$g_ibpb_enabled" = 2 ]; then if [ "$g_ibpb_enabled" = 2 ]; then
# if ibpb=2, ibrs is forcefully=0 # if ibpb=2, ibrs is forcefully=0
pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints" pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints"
@@ -471,7 +471,7 @@ check_CVE_2017_5715_linux() {
fi fi
pr_info_nol " * IBPB enabled and active: " pr_info_nol " * IBPB enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
case "$g_ibpb_enabled" in case "$g_ibpb_enabled" in
"") "")
if [ "$g_ibrs_supported" = 1 ]; then if [ "$g_ibrs_supported" = 1 ]; then
@@ -554,7 +554,7 @@ check_CVE_2017_5715_linux() {
# #
# since 5.15.28, this is now "Retpolines" as the implementation was switched to a generic one, # since 5.15.28, this is now "Retpolines" as the implementation was switched to a generic one,
# so we look for both "retpoline" and "retpolines" # so we look for both "retpoline" and "retpolines"
if [ "$g_mode" = live ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then if [ "$opt_runtime" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then
if echo "$ret_sys_interface_check_fullmsg" | grep -qwi -e retpoline -e retpolines; then if echo "$ret_sys_interface_check_fullmsg" | grep -qwi -e retpoline -e retpolines; then
if echo "$ret_sys_interface_check_fullmsg" | grep -qwi minimal; then if echo "$ret_sys_interface_check_fullmsg" | grep -qwi minimal; then
retpoline_compiler=0 retpoline_compiler=0
@@ -605,7 +605,7 @@ check_CVE_2017_5715_linux() {
# only Red Hat has a tunable to disable it on runtime # only Red Hat has a tunable to disable it on runtime
retp_enabled=-1 retp_enabled=-1
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -e "$g_specex_knob_dir/retp_enabled" ]; then if [ -e "$g_specex_knob_dir/retp_enabled" ]; then
retp_enabled=$(cat "$g_specex_knob_dir/retp_enabled" 2>/dev/null) retp_enabled=$(cat "$g_specex_knob_dir/retp_enabled" 2>/dev/null)
pr_debug "retpoline: found $g_specex_knob_dir/retp_enabled=$retp_enabled" pr_debug "retpoline: found $g_specex_knob_dir/retp_enabled=$retp_enabled"
@@ -635,7 +635,7 @@ check_CVE_2017_5715_linux() {
if is_vulnerable_to_empty_rsb || [ "$opt_verbose" -ge 2 ]; then if is_vulnerable_to_empty_rsb || [ "$opt_verbose" -ge 2 ]; then
pr_info_nol " * Kernel supports RSB filling: " pr_info_nol " * Kernel supports RSB filling: "
rsb_filling=0 rsb_filling=0
if [ "$g_mode" = live ] && [ "$opt_no_sysfs" != 1 ]; then if [ "$opt_runtime" = 1 ] && [ "$opt_no_sysfs" != 1 ]; then
# if we're live and we aren't denied looking into /sys, let's do it # if we're live and we aren't denied looking into /sys, let's do it
if echo "$ret_sys_interface_check_fullmsg" | grep -qw RSB; then if echo "$ret_sys_interface_check_fullmsg" | grep -qw RSB; then
rsb_filling=1 rsb_filling=1
@@ -728,7 +728,7 @@ check_CVE_2017_5715_linux() {
*", IBPB"* | *"; IBPB"*) v2_ibpb_mode=conditional ;; *", IBPB"* | *"; IBPB"*) v2_ibpb_mode=conditional ;;
*) v2_ibpb_mode=disabled ;; *) v2_ibpb_mode=disabled ;;
esac esac
elif [ "$g_mode" = live ]; then elif [ "$opt_runtime" = 1 ]; then
case "$g_ibpb_enabled" in case "$g_ibpb_enabled" in
2) v2_ibpb_mode=always-on ;; 2) v2_ibpb_mode=always-on ;;
1) v2_ibpb_mode=conditional ;; 1) v2_ibpb_mode=conditional ;;
@@ -826,7 +826,7 @@ check_CVE_2017_5715_linux() {
*"PBRSB-eIBRS: Vulnerable"*) v2_pbrsb_status=vulnerable ;; *"PBRSB-eIBRS: Vulnerable"*) v2_pbrsb_status=vulnerable ;;
*) v2_pbrsb_status=unknown ;; *) v2_pbrsb_status=unknown ;;
esac esac
elif [ "$g_mode" != live ] && [ -n "$g_kernel" ]; then elif [ "$opt_runtime" != 1 ] && [ -n "$g_kernel" ]; then
if grep -q 'PBRSB-eIBRS' "$g_kernel" 2>/dev/null; then if grep -q 'PBRSB-eIBRS' "$g_kernel" 2>/dev/null; then
v2_pbrsb_status=sw-sequence v2_pbrsb_status=sw-sequence
else else
@@ -857,7 +857,7 @@ check_CVE_2017_5715_linux() {
*"BHI: Vulnerable"*) v2_bhi_status=vulnerable ;; *"BHI: Vulnerable"*) v2_bhi_status=vulnerable ;;
*) v2_bhi_status=unknown ;; *) v2_bhi_status=unknown ;;
esac esac
elif [ "$g_mode" != live ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then elif [ "$opt_runtime" != 1 ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then
if grep -q '^CONFIG_\(MITIGATION_\)\?SPECTRE_BHI' "$opt_config"; then if grep -q '^CONFIG_\(MITIGATION_\)\?SPECTRE_BHI' "$opt_config"; then
if [ "$cap_bhi" = 1 ]; then if [ "$cap_bhi" = 1 ]; then
v2_bhi_status=bhi_dis_s v2_bhi_status=bhi_dis_s
@@ -881,7 +881,7 @@ check_CVE_2017_5715_linux() {
esac esac
# --- v2_vuln_module --- # --- v2_vuln_module ---
if [ "$g_mode" = live ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then if [ "$opt_runtime" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then
pr_info_nol " * Non-retpoline module loaded: " pr_info_nol " * Non-retpoline module loaded: "
if echo "$ret_sys_interface_check_fullmsg" | grep -q 'vulnerable module loaded'; then if echo "$ret_sys_interface_check_fullmsg" | grep -q 'vulnerable module loaded'; then
v2_vuln_module=1 v2_vuln_module=1
@@ -982,7 +982,7 @@ check_CVE_2017_5715_linux() {
if [ -n "${SMC_MOCK_UNPRIVILEGED_BPF_DISABLED:-}" ]; then if [ -n "${SMC_MOCK_UNPRIVILEGED_BPF_DISABLED:-}" ]; then
_ebpf_disabled="$SMC_MOCK_UNPRIVILEGED_BPF_DISABLED" _ebpf_disabled="$SMC_MOCK_UNPRIVILEGED_BPF_DISABLED"
g_mocked=1 g_mocked=1
elif [ "$g_mode" = live ] && [ -r "$g_procfs/sys/kernel/unprivileged_bpf_disabled" ]; then elif [ "$opt_runtime" = 1 ] && [ -r "$g_procfs/sys/kernel/unprivileged_bpf_disabled" ]; then
_ebpf_disabled=$(cat "$g_procfs/sys/kernel/unprivileged_bpf_disabled" 2>/dev/null) _ebpf_disabled=$(cat "$g_procfs/sys/kernel/unprivileged_bpf_disabled" 2>/dev/null)
g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_UNPRIVILEGED_BPF_DISABLED='$_ebpf_disabled'") g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_UNPRIVILEGED_BPF_DISABLED='$_ebpf_disabled'")
fi fi
@@ -1170,7 +1170,7 @@ check_CVE_2017_5715_linux() {
pvulnstatus "$cve" OK "Full IBPB is mitigating the vulnerability" pvulnstatus "$cve" OK "Full IBPB is mitigating the vulnerability"
# No-runtime mode fallback # No-runtime mode fallback
elif [ "$g_mode" != live ]; then elif [ "$opt_runtime" != 1 ]; then
if [ "$retpoline" = 1 ] && [ -n "$g_ibpb_supported" ]; then if [ "$retpoline" = 1 ] && [ -n "$g_ibpb_supported" ]; then
pvulnstatus "$cve" OK "no-runtime mode: kernel supports retpoline + IBPB to mitigate the vulnerability" pvulnstatus "$cve" OK "no-runtime mode: kernel supports retpoline + IBPB to mitigate the vulnerability"
elif [ -n "$g_ibrs_supported" ] && [ -n "$g_ibpb_supported" ]; then elif [ -n "$g_ibrs_supported" ] && [ -n "$g_ibpb_supported" ]; then

View File

@@ -101,48 +101,60 @@ check_CVE_2017_5753_linux() {
# For no-runtime analysis of these old kernels, match the specific instruction patterns. # For no-runtime analysis of these old kernels, match the specific instruction patterns.
if [ -z "$v1_kernel_mitigated" ]; then if [ -z "$v1_kernel_mitigated" ]; then
pr_info_nol "* Kernel has array_index_mask_nospec (v4.15 binary pattern): " pr_info_nol "* Kernel has array_index_mask_nospec (v4.15 binary pattern): "
# vanilla: look for the Linus' mask aka array_index_mask_nospec()
# that is inlined at least in raw_copy_from_user (__get_user_X symbols)
#mov PER_CPU_VAR(current_task), %_ASM_DX
#cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
#jae bad_get_user
# /* array_index_mask_nospec() are the 2 opcodes that follow */
#+sbb %_ASM_DX, %_ASM_DX
#+and %_ASM_DX, %_ASM_AX
#ASM_STAC
# x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0)
# x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0)
#
# arm32
##ifdef CONFIG_THUMB2_KERNEL
##define CSDB ".inst.w 0xf3af8014"
##else
##define CSDB ".inst 0xe320f014" e320f014
##endif
#asm volatile(
# "cmp %1, %2\n" e1500003
#" sbc %0, %1, %1\n" e0c03000
#CSDB
#: "=r" (mask)
#: "r" (idx), "Ir" (sz)
#: "cc");
#
# http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=spectre&id=a78d156587931a2c3b354534aa772febf6c9e855
v1_mask_nospec='' v1_mask_nospec=''
if [ -n "$g_kernel_err" ]; then if [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)" pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
elif is_x86_kernel; then elif ! command -v perl >/dev/null 2>&1; then
# x86: binary pattern matching for array_index_mask_nospec() pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
# x86 64bits: jae(0x0f 0x83 ....) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0) else
# x86 32bits: cmp(0x3b 0x82 .. .. 0x00 0x00) jae(0x73 ..) sbb(0x19 0xd2) and(0x21 0xd0) perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel"
if ! command -v perl >/dev/null 2>&1; then ret=$?
pstatus yellow UNKNOWN "missing 'perl' binary, please install it" if [ "$ret" -eq 0 ]; then
pstatus green YES "x86 64 bits array_index_mask_nospec()"
v1_mask_nospec="x86 64 bits array_index_mask_nospec"
else else
perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel" perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel"
ret=$? ret=$?
if [ "$ret" -eq 0 ]; then if [ "$ret" -eq 0 ]; then
pstatus green YES "x86 64 bits array_index_mask_nospec()" pstatus green YES "x86 32 bits array_index_mask_nospec()"
v1_mask_nospec="x86 64 bits array_index_mask_nospec" v1_mask_nospec="x86 32 bits array_index_mask_nospec"
else else
perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel" ret=$("${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | grep -w -e f3af8014 -e e320f014 -B2 | grep -B1 -w sbc | grep -w -c cmp)
ret=$? if [ "$ret" -gt 0 ]; then
if [ "$ret" -eq 0 ]; then pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()"
pstatus green YES "x86 32 bits array_index_mask_nospec()" v1_mask_nospec="arm 32 bits array_index_mask_nospec"
v1_mask_nospec="x86 32 bits array_index_mask_nospec"
else else
pstatus yellow NO pstatus yellow NO
fi fi
fi fi
fi fi
elif is_arm_kernel; then
# arm32: match CSDB instruction (0xf3af8014 Thumb2 or 0xe320f014 ARM) preceded by sbc+cmp
# http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=spectre&id=a78d156587931a2c3b354534aa772febf6c9e855
if ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
else
ret=$("${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | grep -w -e f3af8014 -e e320f014 -B2 | grep -B1 -w sbc | grep -w -c cmp)
if [ "$ret" -gt 0 ]; then
pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()"
v1_mask_nospec="arm 32 bits array_index_mask_nospec"
else
pstatus yellow NO
fi
fi
else
pstatus yellow NO
fi fi
fi fi
@@ -160,69 +172,67 @@ check_CVE_2017_5753_linux() {
pstatus yellow NO pstatus yellow NO
fi fi
if is_arm_kernel; then pr_info_nol "* Kernel has mask_nospec64 (arm64): "
pr_info_nol "* Kernel has mask_nospec64 (arm64): " #.macro mask_nospec64, idx, limit, tmp
#.macro mask_nospec64, idx, limit, tmp #sub \tmp, \idx, \limit
#sub \tmp, \idx, \limit #bic \tmp, \tmp, \idx
#bic \tmp, \tmp, \idx #and \idx, \idx, \tmp, asr #63
#and \idx, \idx, \tmp, asr #63 #csdb
#csdb #.endm
#.endm #$ aarch64-linux-gnu-objdump -d vmlinux | grep -w bic -A1 -B1 | grep -w sub -A2 | grep -w and -B2
#$ aarch64-linux-gnu-objdump -d vmlinux | grep -w bic -A1 -B1 | grep -w sub -A2 | grep -w and -B2 #ffffff8008082e44: cb190353 sub x19, x26, x25
#ffffff8008082e44: cb190353 sub x19, x26, x25 #ffffff8008082e48: 8a3a0273 bic x19, x19, x26
#ffffff8008082e48: 8a3a0273 bic x19, x19, x26 #ffffff8008082e4c: 8a93ff5a and x26, x26, x19, asr #63
#ffffff8008082e4c: 8a93ff5a and x26, x26, x19, asr #63 #ffffff8008082e50: d503229f hint #0x14
#ffffff8008082e50: d503229f hint #0x14 # /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump #
# # if we already have a detection, don't bother disassembling the kernel, the answer is no.
# if we already have a detection, don't bother disassembling the kernel, the answer is no. if [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
if [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then pstatus yellow NO
pstatus yellow NO elif [ -n "$g_kernel_err" ]; then
elif [ -n "$g_kernel_err" ]; then pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)" elif ! command -v perl >/dev/null 2>&1; then
elif ! command -v perl >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
pstatus yellow UNKNOWN "missing 'perl' binary, please install it" elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package" else
"${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\ssub\s+(x\d+)/ && $r[1]=~/\sbic\s+$1,\s+$1,/ && $r[2]=~/\sand\s/ && exit(9); shift @r if @r>3'
ret=$?
if [ "$ret" -eq 9 ]; then
pstatus green YES "mask_nospec64 macro is present and used"
v1_mask_nospec="arm64 mask_nospec64"
else else
"${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\ssub\s+(x\d+)/ && $r[1]=~/\sbic\s+$1,\s+$1,/ && $r[2]=~/\sand\s/ && exit(9); shift @r if @r>3' pstatus yellow NO
ret=$?
if [ "$ret" -eq 9 ]; then
pstatus green YES "mask_nospec64 macro is present and used"
v1_mask_nospec="arm64 mask_nospec64"
else
pstatus yellow NO
fi
fi fi
fi
pr_info_nol "* Kernel has array_index_nospec (arm64): " pr_info_nol "* Kernel has array_index_nospec (arm64): "
# in 4.19+ kernels, the mask_nospec64 asm64 macro is replaced by array_index_nospec, defined in nospec.h, and used in invoke_syscall() # in 4.19+ kernels, the mask_nospec64 asm64 macro is replaced by array_index_nospec, defined in nospec.h, and used in invoke_syscall()
# ffffff8008090a4c: 2a0203e2 mov w2, w2 # ffffff8008090a4c: 2a0203e2 mov w2, w2
# ffffff8008090a50: eb0200bf cmp x5, x2 # ffffff8008090a50: eb0200bf cmp x5, x2
# ffffff8008090a54: da1f03e2 ngc x2, xzr # ffffff8008090a54: da1f03e2 ngc x2, xzr
# ffffff8008090a58: d503229f hint #0x14 # ffffff8008090a58: d503229f hint #0x14
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump # /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
# #
# if we already have a detection, don't bother disassembling the kernel, the answer is no. # if we already have a detection, don't bother disassembling the kernel, the answer is no.
if [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then if [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
pstatus yellow NO pstatus yellow NO
elif [ -n "$g_kernel_err" ]; then elif [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)" pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
elif ! command -v perl >/dev/null 2>&1; then elif ! command -v perl >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing 'perl' binary, please install it" pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package" pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
else
"${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\smov\s+(w\d+),\s+(w\d+)/ && $r[1]=~/\scmp\s+(x\d+),\s+(x\d+)/ && $r[2]=~/\sngc\s+$2,/ && exit(9); shift @r if @r>3'
ret=$?
if [ "$ret" -eq 9 ]; then
pstatus green YES "array_index_nospec macro is present and used"
v1_mask_nospec="arm64 array_index_nospec"
else else
"${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\smov\s+(w\d+),\s+(w\d+)/ && $r[1]=~/\scmp\s+(x\d+),\s+(x\d+)/ && $r[2]=~/\sngc\s+$2,/ && exit(9); shift @r if @r>3' pstatus yellow NO
ret=$?
if [ "$ret" -eq 9 ]; then
pstatus green YES "array_index_nospec macro is present and used"
v1_mask_nospec="arm64 array_index_nospec"
else
pstatus yellow NO
fi
fi fi
fi # is_arm_kernel fi
elif [ "$sys_interface_available" = 0 ]; then elif [ "$sys_interface_available" = 0 ]; then
msg="/sys vulnerability interface use forced, but it's not available!" msg="/sys vulnerability interface use forced, but it's not available!"

View File

@@ -104,7 +104,7 @@ check_CVE_2017_5754_linux() {
mount_debugfs mount_debugfs
pr_info_nol " * PTI enabled and active: " pr_info_nol " * PTI enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
dmesg_grep="Kernel/User page tables isolation: enabled" dmesg_grep="Kernel/User page tables isolation: enabled"
dmesg_grep="$dmesg_grep|Kernel page table isolation enabled" dmesg_grep="$dmesg_grep|Kernel page table isolation enabled"
dmesg_grep="$dmesg_grep|x86/pti: Unmapping kernel while in userspace" dmesg_grep="$dmesg_grep|x86/pti: Unmapping kernel while in userspace"
@@ -170,7 +170,7 @@ check_CVE_2017_5754_linux() {
is_xen_dom0 && xen_pv_domo=1 is_xen_dom0 && xen_pv_domo=1
is_xen_domU && xen_pv_domu=1 is_xen_domU && xen_pv_domu=1
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# checking whether we're running under Xen PV 64 bits. If yes, we are affected by affected_variant3 # checking whether we're running under Xen PV 64 bits. If yes, we are affected by affected_variant3
# (unless we are a Dom0) # (unless we are a Dom0)
pr_info_nol "* Running as a Xen PV DomU: " pr_info_nol "* Running as a Xen PV DomU: "
@@ -186,7 +186,7 @@ check_CVE_2017_5754_linux() {
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected" pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
elif [ -z "$msg" ]; then elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ "$kpti_enabled" = 1 ]; then if [ "$kpti_enabled" = 1 ]; then
pvulnstatus "$cve" OK "PTI mitigates the vulnerability" pvulnstatus "$cve" OK "PTI mitigates the vulnerability"
elif [ "$xen_pv_domo" = 1 ]; then elif [ "$xen_pv_domo" = 1 ]; then

View File

@@ -36,7 +36,7 @@ check_CVE_2018_12207_linux() {
fi fi
pr_info_nol "* iTLB Multihit mitigation enabled and active: " pr_info_nol "* iTLB Multihit mitigation enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -n "$ret_sys_interface_check_fullmsg" ]; then if [ -n "$ret_sys_interface_check_fullmsg" ]; then
if echo "$ret_sys_interface_check_fullmsg" | grep -qF 'Mitigation'; then if echo "$ret_sys_interface_check_fullmsg" | grep -qF 'Mitigation'; then
pstatus green YES "$ret_sys_interface_check_fullmsg" pstatus green YES "$ret_sys_interface_check_fullmsg"
@@ -63,7 +63,7 @@ check_CVE_2018_12207_linux() {
elif [ -z "$msg" ]; then elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old # if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old
pvulnstatus "$cve" VULN "Your kernel doesn't support iTLB Multihit mitigation, update it" pvulnstatus "$cve" VULN "Your kernel doesn't support iTLB Multihit mitigation, update it"
else else

View File

@@ -37,7 +37,7 @@ check_CVE_2018_3620_linux() {
fi fi
pr_info_nol "* PTE inversion enabled and active: " pr_info_nol "* PTE inversion enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -n "$ret_sys_interface_check_fullmsg" ]; then if [ -n "$ret_sys_interface_check_fullmsg" ]; then
if echo "$ret_sys_interface_check_fullmsg" | grep -q 'Mitigation: PTE Inversion'; then if echo "$ret_sys_interface_check_fullmsg" | grep -q 'Mitigation: PTE Inversion'; then
pstatus green YES pstatus green YES
@@ -66,7 +66,7 @@ check_CVE_2018_3620_linux() {
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
if [ "$pteinv_supported" = 1 ]; then if [ "$pteinv_supported" = 1 ]; then
if [ "$pteinv_active" = 1 ] || [ "$g_mode" != live ]; then if [ "$pteinv_active" = 1 ] || [ "$opt_runtime" != 1 ]; then
pvulnstatus "$cve" OK "PTE inversion mitigates the vulnerability" pvulnstatus "$cve" OK "PTE inversion mitigates the vulnerability"
else else
pvulnstatus "$cve" VULN "Your kernel supports PTE inversion but it doesn't seem to be enabled" pvulnstatus "$cve" VULN "Your kernel supports PTE inversion but it doesn't seem to be enabled"

View File

@@ -18,7 +18,7 @@ check_CVE_2018_3639_linux() {
fi fi
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
pr_info_nol "* Kernel supports disabling speculative store bypass (SSB): " pr_info_nol "* Kernel supports disabling speculative store bypass (SSB): "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if grep -Eq 'Speculation.?Store.?Bypass:' "$g_procfs/self/status" 2>/dev/null; then if grep -Eq 'Speculation.?Store.?Bypass:' "$g_procfs/self/status" 2>/dev/null; then
kernel_ssb="found in $g_procfs/self/status" kernel_ssb="found in $g_procfs/self/status"
pr_debug "found Speculation.Store.Bypass: in $g_procfs/self/status" pr_debug "found Speculation.Store.Bypass: in $g_procfs/self/status"
@@ -57,7 +57,7 @@ check_CVE_2018_3639_linux() {
fi fi
kernel_ssbd_enabled=-1 kernel_ssbd_enabled=-1
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# https://elixir.bootlin.com/linux/v5.0/source/fs/proc/array.c#L340 # https://elixir.bootlin.com/linux/v5.0/source/fs/proc/array.c#L340
pr_info_nol "* SSB mitigation is enabled and active: " pr_info_nol "* SSB mitigation is enabled and active: "
if grep -Eq 'Speculation.?Store.?Bypass:[[:space:]]+thread' "$g_procfs/self/status" 2>/dev/null; then if grep -Eq 'Speculation.?Store.?Bypass:[[:space:]]+thread' "$g_procfs/self/status" 2>/dev/null; then
@@ -106,7 +106,7 @@ check_CVE_2018_3639_linux() {
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
if [ -n "$cap_ssbd" ]; then if [ -n "$cap_ssbd" ]; then
if [ -n "$kernel_ssb" ]; then if [ -n "$kernel_ssb" ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ "$kernel_ssbd_enabled" -gt 0 ]; then if [ "$kernel_ssbd_enabled" -gt 0 ]; then
pvulnstatus "$cve" OK "your CPU and kernel both support SSBD and mitigation is enabled" pvulnstatus "$cve" OK "your CPU and kernel both support SSBD and mitigation is enabled"
else else

View File

@@ -69,19 +69,14 @@ check_CVE_2018_3646_linux() {
pr_info "* Mitigation 1 (KVM)" pr_info "* Mitigation 1 (KVM)"
pr_info_nol " * EPT is disabled: " pr_info_nol " * EPT is disabled: "
ept_disabled=-1 ept_disabled=-1
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if ! [ -r "$SYS_MODULE_BASE/kvm_intel/parameters/ept" ]; then if ! [ -r "$SYS_MODULE_BASE/kvm_intel/parameters/ept" ]; then
pstatus blue N/A "the kvm_intel module is not loaded" pstatus blue N/A "the kvm_intel module is not loaded"
elif [ "$(cat "$SYS_MODULE_BASE/kvm_intel/parameters/ept")" = N ]; then
pstatus green YES
ept_disabled=1
else else
ept_value="$(cat "$SYS_MODULE_BASE/kvm_intel/parameters/ept" 2>/dev/null || echo ERROR)" pstatus yellow NO
if [ "$ept_value" = N ]; then
pstatus green YES
ept_disabled=1
elif [ "$ept_value" = ERROR ]; then
pstatus yellow UNK "Couldn't read $SYS_MODULE_BASE/kvm_intel/parameters/ept"
else
pstatus yellow NO
fi
fi fi
else else
pstatus blue N/A "not testable in no-runtime mode" pstatus blue N/A "not testable in no-runtime mode"
@@ -89,7 +84,7 @@ check_CVE_2018_3646_linux() {
pr_info "* Mitigation 2" pr_info "* Mitigation 2"
pr_info_nol " * L1D flush is supported by kernel: " pr_info_nol " * L1D flush is supported by kernel: "
if [ "$g_mode" = live ] && grep -qw flush_l1d "$g_procfs/cpuinfo"; then if [ "$opt_runtime" = 1 ] && grep -qw flush_l1d "$g_procfs/cpuinfo"; then
l1d_kernel="found flush_l1d in $g_procfs/cpuinfo" l1d_kernel="found flush_l1d in $g_procfs/cpuinfo"
fi fi
if [ -z "$l1d_kernel" ]; then if [ -z "$l1d_kernel" ]; then
@@ -111,7 +106,7 @@ check_CVE_2018_3646_linux() {
fi fi
pr_info_nol " * L1D flush enabled: " pr_info_nol " * L1D flush enabled: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -n "$ret_sys_interface_check_fullmsg" ]; then if [ -n "$ret_sys_interface_check_fullmsg" ]; then
# vanilla: VMX: $l1dstatus, SMT $smtstatus # vanilla: VMX: $l1dstatus, SMT $smtstatus
# Red Hat: VMX: SMT $smtstatus, L1D $l1dstatus # Red Hat: VMX: SMT $smtstatus, L1D $l1dstatus
@@ -161,7 +156,7 @@ check_CVE_2018_3646_linux() {
fi fi
pr_info_nol " * Hardware-backed L1D flush supported: " pr_info_nol " * Hardware-backed L1D flush supported: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if grep -qw flush_l1d "$g_procfs/cpuinfo" || [ -n "$l1d_xen_hardware" ]; then if grep -qw flush_l1d "$g_procfs/cpuinfo" || [ -n "$l1d_xen_hardware" ]; then
pstatus green YES "performance impact of the mitigation will be greatly reduced" pstatus green YES "performance impact of the mitigation will be greatly reduced"
else else

View File

@@ -33,7 +33,7 @@ check_CVE_2019_11135_linux() {
fi fi
pr_info_nol "* TAA mitigation enabled and active: " pr_info_nol "* TAA mitigation enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -n "$ret_sys_interface_check_fullmsg" ]; then if [ -n "$ret_sys_interface_check_fullmsg" ]; then
if echo "$ret_sys_interface_check_fullmsg" | grep -qE '^Mitigation'; then if echo "$ret_sys_interface_check_fullmsg" | grep -qE '^Mitigation'; then
pstatus green YES "$ret_sys_interface_check_fullmsg" pstatus green YES "$ret_sys_interface_check_fullmsg"
@@ -57,7 +57,7 @@ check_CVE_2019_11135_linux() {
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected" pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
elif [ -z "$msg" ]; then elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old # if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old
pvulnstatus "$cve" VULN "Your kernel doesn't support TAA mitigation, update it" pvulnstatus "$cve" VULN "Your kernel doesn't support TAA mitigation, update it"
else else

View File

@@ -32,7 +32,7 @@ check_CVE_2020_0543_linux() {
pstatus yellow NO pstatus yellow NO
fi fi
pr_info_nol "* SRBDS mitigation control is enabled and active: " pr_info_nol "* SRBDS mitigation control is enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -n "$ret_sys_interface_check_fullmsg" ]; then if [ -n "$ret_sys_interface_check_fullmsg" ]; then
if echo "$ret_sys_interface_check_fullmsg" | grep -qE '^Mitigation'; then if echo "$ret_sys_interface_check_fullmsg" | grep -qE '^Mitigation'; then
pstatus green YES "$ret_sys_interface_check_fullmsg" pstatus green YES "$ret_sys_interface_check_fullmsg"
@@ -61,7 +61,7 @@ check_CVE_2020_0543_linux() {
# SRBDS mitigation control is enabled # SRBDS mitigation control is enabled
if [ -z "$msg" ]; then if [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old # if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old
pvulnstatus "$cve" OK "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated" pvulnstatus "$cve" OK "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated"
fi fi
@@ -75,7 +75,7 @@ check_CVE_2020_0543_linux() {
elif [ "$cap_srbds_on" = 0 ]; then elif [ "$cap_srbds_on" = 0 ]; then
# SRBDS mitigation control is disabled # SRBDS mitigation control is disabled
if [ -z "$msg" ]; then if [ -z "$msg" ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old # if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old
pvulnstatus "$cve" VULN "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated. Mitigation is disabled" pvulnstatus "$cve" VULN "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated. Mitigation is disabled"
fi fi

View File

@@ -174,7 +174,7 @@ check_CVE_2022_29900_linux() {
# Zen/Zen+/Zen2: check IBPB microcode support and SMT # Zen/Zen+/Zen2: check IBPB microcode support and SMT
if [ "$cpu_family" = $((0x17)) ]; then if [ "$cpu_family" = $((0x17)) ]; then
pr_info_nol "* CPU supports IBPB: " pr_info_nol "* CPU supports IBPB: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -n "$cap_ibpb" ]; then if [ -n "$cap_ibpb" ]; then
pstatus green YES "$cap_ibpb" pstatus green YES "$cap_ibpb"
else else
@@ -217,7 +217,7 @@ check_CVE_2022_29900_linux() {
"doesn't fully protect cross-thread speculation." "doesn't fully protect cross-thread speculation."
elif [ -z "$kernel_unret" ] && [ -z "$kernel_ibpb_entry" ]; then elif [ -z "$kernel_unret" ] && [ -z "$kernel_ibpb_entry" ]; then
pvulnstatus "$cve" VULN "Your kernel doesn't have either UNRET_ENTRY or IBPB_ENTRY compiled-in" pvulnstatus "$cve" VULN "Your kernel doesn't have either UNRET_ENTRY or IBPB_ENTRY compiled-in"
elif [ "$smt_enabled" = 0 ] && [ -z "$cap_ibpb" ] && [ "$g_mode" = live ]; then elif [ "$smt_enabled" = 0 ] && [ -z "$cap_ibpb" ] && [ "$opt_runtime" = 1 ]; then
pvulnstatus "$cve" VULN "SMT is enabled and your microcode doesn't support IBPB" pvulnstatus "$cve" VULN "SMT is enabled and your microcode doesn't support IBPB"
explain "Update your CPU microcode to get IBPB support, or disable SMT by adding\n" \ explain "Update your CPU microcode to get IBPB support, or disable SMT by adding\n" \
"\`nosmt\` to your kernel command line." "\`nosmt\` to your kernel command line."

View File

@@ -84,7 +84,7 @@ check_CVE_2022_29901_linux() {
fi fi
pr_info_nol "* CPU supports Enhanced IBRS (IBRS_ALL): " pr_info_nol "* CPU supports Enhanced IBRS (IBRS_ALL): "
if [ "$g_mode" = live ] || [ "$cap_ibrs_all" != -1 ]; then if [ "$opt_runtime" = 1 ] || [ "$cap_ibrs_all" != -1 ]; then
if [ "$cap_ibrs_all" = 1 ]; then if [ "$cap_ibrs_all" = 1 ]; then
pstatus green YES pstatus green YES
elif [ "$cap_ibrs_all" = 0 ]; then elif [ "$cap_ibrs_all" = 0 ]; then
@@ -97,7 +97,7 @@ check_CVE_2022_29901_linux() {
fi fi
pr_info_nol "* CPU has RSB Alternate Behavior (RSBA): " pr_info_nol "* CPU has RSB Alternate Behavior (RSBA): "
if [ "$g_mode" = live ] || [ "$cap_rsba" != -1 ]; then if [ "$opt_runtime" = 1 ] || [ "$cap_rsba" != -1 ]; then
if [ "$cap_rsba" = 1 ]; then if [ "$cap_rsba" = 1 ]; then
pstatus yellow YES "this CPU is affected by RSB underflow" pstatus yellow YES "this CPU is affected by RSB underflow"
elif [ "$cap_rsba" = 0 ]; then elif [ "$cap_rsba" = 0 ]; then

View File

@@ -145,7 +145,7 @@ check_CVE_2022_40982_linux() {
if [ -n "$kernel_gds" ]; then if [ -n "$kernel_gds" ]; then
pr_info_nol "* Kernel has disabled AVX as a mitigation: " pr_info_nol "* Kernel has disabled AVX as a mitigation: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# Check dmesg message to see whether AVX has been disabled # Check dmesg message to see whether AVX has been disabled
dmesg_grep 'Microcode update needed! Disabling AVX as mitigation' dmesg_grep 'Microcode update needed! Disabling AVX as mitigation'
dmesgret=$? dmesgret=$?

View File

@@ -101,7 +101,7 @@ check_CVE_2023_20588_linux() {
pr_info_nol "* DIV0 mitigation enabled and active: " pr_info_nol "* DIV0 mitigation enabled and active: "
cpuinfo_div0='' cpuinfo_div0=''
dmesg_div0='' dmesg_div0=''
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ -e "$g_procfs/cpuinfo" ] && grep -qw 'div0' "$g_procfs/cpuinfo" 2>/dev/null; then if [ -e "$g_procfs/cpuinfo" ] && grep -qw 'div0' "$g_procfs/cpuinfo" 2>/dev/null; then
cpuinfo_div0=1 cpuinfo_div0=1
pstatus green YES "div0 found in $g_procfs/cpuinfo bug flags" pstatus green YES "div0 found in $g_procfs/cpuinfo bug flags"
@@ -141,7 +141,7 @@ check_CVE_2023_20588_linux() {
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected" pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
elif [ -z "$msg" ]; then elif [ -z "$msg" ]; then
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# live mode: cpuinfo div0 flag is the strongest proof the mitigation is active # live mode: cpuinfo div0 flag is the strongest proof the mitigation is active
if [ "$cpuinfo_div0" = 1 ] || [ "$dmesg_div0" = 1 ]; then if [ "$cpuinfo_div0" = 1 ] || [ "$dmesg_div0" = 1 ]; then
_cve_2023_20588_pvulnstatus_smt _cve_2023_20588_pvulnstatus_smt

View File

@@ -28,7 +28,7 @@ check_CVE_2023_20593_linux() {
pstatus yellow NO pstatus yellow NO
fi fi
pr_info_nol "* Zenbleed kernel mitigation enabled and active: " pr_info_nol "* Zenbleed kernel mitigation enabled and active: "
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
# read the DE_CFG MSR, we want to check the 9th bit # read the DE_CFG MSR, we want to check the 9th bit
# don't do it on non-Zen2 AMD CPUs or later, aka Family 17h, # don't do it on non-Zen2 AMD CPUs or later, aka Family 17h,
# as the behavior could be unknown on others # as the behavior could be unknown on others
@@ -82,7 +82,7 @@ check_CVE_2023_20593_linux() {
elif [ -z "$msg" ]; then elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
zenbleed_print_vuln=0 zenbleed_print_vuln=0
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ "$fp_backup_fix" = 1 ] && [ "$ucode_zenbleed" = 1 ]; then if [ "$fp_backup_fix" = 1 ] && [ "$ucode_zenbleed" = 1 ]; then
# this should never happen, but if it does, it's interesting to know # this should never happen, but if it does, it's interesting to know
pvulnstatus "$cve" OK "Both your CPU microcode and kernel are mitigating Zenbleed" pvulnstatus "$cve" OK "Both your CPU microcode and kernel are mitigating Zenbleed"

View File

@@ -69,48 +69,44 @@ check_CVE_2023_28746_linux() {
fi fi
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
if is_x86_cpu; then pr_info_nol "* CPU microcode mitigates the vulnerability: "
pr_info_nol "* CPU microcode mitigates the vulnerability: " if [ "$cap_rfds_clear" = 1 ]; then
if [ "$cap_rfds_clear" = 1 ]; then pstatus green YES "RFDS_CLEAR capability indicated by microcode"
pstatus green YES "RFDS_CLEAR capability indicated by microcode" elif [ "$cap_rfds_clear" = 0 ]; then
elif [ "$cap_rfds_clear" = 0 ]; then pstatus yellow NO
pstatus yellow NO else
else pstatus yellow UNKNOWN "couldn't read MSR"
pstatus yellow UNKNOWN "couldn't read MSR"
fi
fi fi
if is_x86_kernel; then pr_info_nol "* Kernel supports RFDS mitigation (VERW on transitions): "
pr_info_nol "* Kernel supports RFDS mitigation (VERW on transitions): " kernel_rfds=''
kernel_rfds='' kernel_rfds_err=''
kernel_rfds_err='' if [ -n "$g_kernel_err" ]; then
if [ -n "$g_kernel_err" ]; then kernel_rfds_err="$g_kernel_err"
kernel_rfds_err="$g_kernel_err" elif is_x86_kernel && grep -q 'Clear Register File' "$g_kernel"; then
elif grep -q 'Clear Register File' "$g_kernel"; then kernel_rfds="found 'Clear Register File' string in kernel image"
kernel_rfds="found 'Clear Register File' string in kernel image" elif is_x86_kernel && grep -q 'reg_file_data_sampling' "$g_kernel"; then
elif grep -q 'reg_file_data_sampling' "$g_kernel"; then kernel_rfds="found reg_file_data_sampling in kernel image"
kernel_rfds="found reg_file_data_sampling in kernel image" fi
fi if [ -z "$kernel_rfds" ] && is_x86_kernel && [ -r "$opt_config" ]; then
if [ -z "$kernel_rfds" ] && [ -r "$opt_config" ]; then if grep -q '^CONFIG_MITIGATION_RFDS=y' "$opt_config"; then
if grep -q '^CONFIG_MITIGATION_RFDS=y' "$opt_config"; then kernel_rfds="RFDS mitigation config option found enabled in kernel config"
kernel_rfds="RFDS mitigation config option found enabled in kernel config"
fi
fi
if [ -z "$kernel_rfds" ] && [ -n "$opt_map" ]; then
if grep -q 'rfds_select_mitigation' "$opt_map"; then
kernel_rfds="found rfds_select_mitigation in System.map"
fi
fi
if [ -n "$kernel_rfds" ]; then
pstatus green YES "$kernel_rfds"
elif [ -n "$kernel_rfds_err" ]; then
pstatus yellow UNKNOWN "$kernel_rfds_err"
else
pstatus yellow NO
fi fi
fi fi
if [ -z "$kernel_rfds" ] && is_x86_kernel && [ -n "$opt_map" ]; then
if grep -q 'rfds_select_mitigation' "$opt_map"; then
kernel_rfds="found rfds_select_mitigation in System.map"
fi
fi
if [ -n "$kernel_rfds" ]; then
pstatus green YES "$kernel_rfds"
elif [ -n "$kernel_rfds_err" ]; then
pstatus yellow UNKNOWN "$kernel_rfds_err"
else
pstatus yellow NO
fi
if is_x86_cpu && [ "$g_mode" = live ] && [ "$sys_interface_available" = 1 ]; then if [ "$opt_runtime" = 1 ] && [ "$sys_interface_available" = 1 ]; then
pr_info_nol "* RFDS mitigation is enabled and active: " pr_info_nol "* RFDS mitigation is enabled and active: "
if echo "$ret_sys_interface_check_fullmsg" | grep -qi '^Mitigation'; then if echo "$ret_sys_interface_check_fullmsg" | grep -qi '^Mitigation'; then
rfds_mitigated=1 rfds_mitigated=1
@@ -133,7 +129,7 @@ check_CVE_2023_28746_linux() {
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
if [ "$cap_rfds_clear" = 1 ]; then if [ "$cap_rfds_clear" = 1 ]; then
if [ -n "$kernel_rfds" ]; then if [ -n "$kernel_rfds" ]; then
if [ "$g_mode" = live ]; then if [ "$opt_runtime" = 1 ]; then
if [ "$rfds_mitigated" = 1 ]; then if [ "$rfds_mitigated" = 1 ]; then
pvulnstatus "$cve" OK "Your microcode and kernel are both up to date for this mitigation, and mitigation is enabled" pvulnstatus "$cve" OK "Your microcode and kernel are both up to date for this mitigation, and mitigation is enabled"
else else

View File

@@ -1,151 +0,0 @@
# 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
}