mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-04-22 08:33:20 +02:00
enh: add FPDSS check for AMD Zen1/Zen+ (CVE-2025-54505)
built from commit 048ce5b6a2
dated 2026-04-18 10:56:21 +0000
by Stéphane Lesimple (speed47_github@speed47.net)
This commit is contained in:
199
.github/workflows/daily_vuln_scan_prompt.md
vendored
Normal file
199
.github/workflows/daily_vuln_scan_prompt.md
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
# Daily transient-execution vulnerability scan
|
||||
|
||||
You are a scheduled agent running inside a GitHub Actions job. Your job
|
||||
is to audit public news/advisory sources for **transient-execution and
|
||||
CPU side-channel vulnerabilities** that may need to be added to
|
||||
**spectre-meltdown-checker** (this repository).
|
||||
|
||||
## What counts as "relevant"
|
||||
|
||||
spectre-meltdown-checker detects, reports, and suggests mitigations for
|
||||
CPU vulnerabilities such as: Spectre v1/v2/v4, Meltdown, Foreshadow/L1TF,
|
||||
MDS (ZombieLoad/RIDL/Fallout), TAA, SRBDS, iTLB Multihit, Zenbleed,
|
||||
Downfall (GDS), Retbleed, Inception, SRSO, BHI, RFDS, Reptar, FP-DSS,
|
||||
and any similar microarchitectural side-channel or speculative-execution
|
||||
issue on x86 (Intel/AMD) or ARM CPUs. It also surfaces related hardware
|
||||
mitigation features (SMAP/SMEP/UMIP/IBPB/eIBRS/STIBP…) when they gate
|
||||
the remediation for a tracked CVE.
|
||||
|
||||
It does **not** track generic software CVEs, GPU driver bugs, networking
|
||||
stacks, filesystem bugs, userspace crypto issues, or unrelated kernel
|
||||
subsystems.
|
||||
|
||||
## Inputs handed to you by the workflow
|
||||
|
||||
- Working directory: the repo root (`/github/workspace` in Actions, or
|
||||
wherever `actions/checkout` placed it). You may `grep` the repo to
|
||||
check whether a CVE or codename is already covered.
|
||||
- `state/seen.json` — memory carried over from the previous run, with
|
||||
shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"last_run": "2026-04-17T08:00:12Z",
|
||||
"seen": {
|
||||
"<stable-id-1>": { "bucket": "unrelated", "seen_at": "2026-04-17T08:00:12Z", "source": "phoronix" },
|
||||
"<stable-id-2>": { "bucket": "tocheck", "seen_at": "2026-04-17T08:00:12Z", "source": "oss-sec", "cve": "CVE-2026-1234" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
On the very first run, or when the prior artifact has expired,
|
||||
the file exists but `seen` is empty and `last_run` is `null`.
|
||||
|
||||
- Environment: `SCAN_DATE` (ISO-8601 timestamp of the run start, set by
|
||||
the workflow). Treat this as "now" for all time-window decisions.
|
||||
|
||||
## Time window
|
||||
|
||||
This is a belt-and-suspenders design — use **both** mechanisms:
|
||||
|
||||
1. **Primary: stable-id dedup.** If an item's stable identifier (see
|
||||
below) is already present in `state.seen`, skip it entirely — it
|
||||
was classified on a previous day.
|
||||
2. **Secondary: 25-hour window.** Among *new* items, prefer those whose
|
||||
publication/update timestamp is within the last 25 h relative to
|
||||
`SCAN_DATE`. This bounds work when the prior artifact expired
|
||||
(90-day retention) or when `last_run` is stale (missed runs).
|
||||
If `last_run` is older than 25 h, widen the window to
|
||||
`now - last_run + 1h` so no items are lost across missed runs.
|
||||
3. Items without a parseable timestamp: include them (fail-safe).
|
||||
|
||||
## Sources to poll
|
||||
|
||||
Fetch each URL with
|
||||
`curl -sS -A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" -L --max-time 20`.
|
||||
On non-2xx or timeout, record the failure in the run summary and
|
||||
continue — do not abort.
|
||||
|
||||
### RSS / Atom feeds (primary — parse feed timestamps)
|
||||
|
||||
| Short name | URL |
|
||||
|-----------------|-----|
|
||||
| phoronix | https://www.phoronix.com/rss.php |
|
||||
| oss-sec | https://seclists.org/rss/oss-sec.rss |
|
||||
| lwn | https://lwn.net/headlines/newrss |
|
||||
| project-zero | https://googleprojectzero.blogspot.com/feeds/posts/default |
|
||||
| vusec | https://www.vusec.net/feed/ |
|
||||
| comsec-eth | https://comsec.ethz.ch/category/news/feed/ |
|
||||
| msrc | https://msrc.microsoft.com/update-guide/rss |
|
||||
| cisa | https://www.cisa.gov/cybersecurity-advisories/all.xml |
|
||||
| cert-cc | https://www.kb.cert.org/vuls/atomfeed/ |
|
||||
|
||||
### HTML pages (no RSS — fetch, extract dated entries)
|
||||
|
||||
| Short name | URL |
|
||||
|-----------------|-----|
|
||||
| intel-psirt | https://www.intel.com/content/www/us/en/security-center/default.html |
|
||||
| amd-psirt | https://www.amd.com/en/resources/product-security.html |
|
||||
| arm-spec | https://developer.arm.com/Arm%20Security%20Center/Speculative%20Processor%20Vulnerability |
|
||||
| transient-fail | https://transient.fail/ |
|
||||
|
||||
For HTML pages: look for advisory tables or listings with dates. Extract
|
||||
the advisory title, permalink, and date. If a page has no dates at all,
|
||||
compare its content against `state.seen` — any new advisory IDs not yet
|
||||
classified count as "new this run".
|
||||
|
||||
## Stable identifier per source
|
||||
|
||||
Use the first available of these, in order, as the dedup key:
|
||||
|
||||
1. Vendor advisory ID (`INTEL-SA-01234`, `AMD-SB-7001`, `ARM-2024-0042`,
|
||||
`VU#123456`, `CVE-YYYY-NNNNN`)
|
||||
2. RSS `<guid>` / Atom `<id>`
|
||||
3. Permalink URL (`<link>`)
|
||||
|
||||
Always also record the permalink URL in the output file so a human can
|
||||
click through.
|
||||
|
||||
## Classification rules
|
||||
|
||||
For each **new** item (not in `state.seen`) that passes the time window,
|
||||
pick exactly one bucket:
|
||||
|
||||
- **toimplement** — a clearly-identified new transient-execution / CPU
|
||||
side-channel vulnerability in scope, **and not already covered by
|
||||
this repo**. Verify the second half by grepping the repo for the CVE
|
||||
ID *and* the codename before classifying; if either matches existing
|
||||
code, demote to `tocheck`.
|
||||
- **tocheck** — plausibly in-scope but ambiguous: mitigation-only
|
||||
feature (LASS, IBT, APIC-virt, etc.); item seemingly already
|
||||
implemented but worth confirming scope; unclear applicability
|
||||
(e.g. embedded-only ARM SKU); CVE-ID pending; contradictory info
|
||||
across sources. State clearly what would resolve the ambiguity.
|
||||
- **unrelated** — everything else.
|
||||
|
||||
Tie-breakers: prefer `tocheck` over `unrelated` when uncertain. Prefer
|
||||
`tocheck` over `toimplement` when the CVE ID is still "reserved" /
|
||||
"pending" — false positives in `toimplement` waste human time more than
|
||||
false positives in `tocheck`.
|
||||
|
||||
## Outputs
|
||||
|
||||
Compute `TODAY=$(date -u -d "$SCAN_DATE" +%F)`. Write these files under
|
||||
the repo root, overwriting if they already exist (they shouldn't unless
|
||||
the workflow re-ran the same day):
|
||||
|
||||
- `rss_${TODAY}_toimplement.md`
|
||||
- `rss_${TODAY}_tocheck.md`
|
||||
- `rss_${TODAY}_unrelated.md`
|
||||
|
||||
Each file uses level-2 headers per source short-name, then one bullet
|
||||
per item: the stable ID (if any), the permalink URL, and 1–2 sentences.
|
||||
Keep entries terse — a human skims these daily.
|
||||
|
||||
```markdown
|
||||
## oss-sec
|
||||
- **CVE-2026-1234** — https://www.openwall.com/lists/oss-security/2026/04/18/3
|
||||
New Intel transient-execution bug "Foo" disclosed today; affects
|
||||
Redwood Cove cores, microcode fix pending. Not yet covered by this
|
||||
repo (grepped for CVE-2026-1234 and "Foo" — no matches).
|
||||
|
||||
## phoronix
|
||||
- https://www.phoronix.com/news/Some-Article
|
||||
Linux 7.2 drops a compiler-target flag; unrelated to CPU side channels.
|
||||
```
|
||||
|
||||
If a bucket has no items, write the file with a single line
|
||||
`(no new items in this window)` so it is obvious the job ran.
|
||||
|
||||
### Run summary
|
||||
|
||||
Append this block to the **tocheck** file (creating it if empty):
|
||||
|
||||
```markdown
|
||||
## Run summary
|
||||
- SCAN_DATE: <value>
|
||||
- window cutoff: <computed cutoff>
|
||||
- prior state size: <N> entries, last_run=<value>
|
||||
- per-source new item counts: phoronix=<n>, oss-sec=<n>, lwn=<n>, ...
|
||||
- fetch failures: <list, or "none">
|
||||
- total classified this run: toimplement=<n>, tocheck=<n>, unrelated=<n>
|
||||
```
|
||||
|
||||
### State update
|
||||
|
||||
Rewrite `state/seen.json` with:
|
||||
|
||||
- `last_run` = `SCAN_DATE`
|
||||
- `seen` = union of (pruned prior `seen`) ∪ (all items classified this
|
||||
run, keyed by stable ID, with `{bucket, seen_at=SCAN_DATE, source, cve?}`)
|
||||
|
||||
Pruning (keep state bounded): drop any entry whose `seen_at` is older
|
||||
than 30 days before `SCAN_DATE`. The workflow step also does this as
|
||||
a safety net, but do it here too so the in-memory view is consistent.
|
||||
|
||||
## Guardrails
|
||||
|
||||
- Do NOT modify any repo source code. Only write the three markdown
|
||||
output files and `state/seen.json`.
|
||||
- Do NOT create commits, branches, or PRs.
|
||||
- Do NOT call any tool that posts externally (Slack, GitHub comments,
|
||||
issues, email, etc.).
|
||||
- Do NOT follow links off-site for deeper investigation unless strictly
|
||||
needed to resolve a `tocheck` ambiguity — budget of at most 5 such
|
||||
follow-ups per run.
|
||||
- If a source returns unexpectedly large content, truncate to the first
|
||||
~200 items before parsing.
|
||||
- If total runtime exceeds 15 minutes, finish whatever you can,
|
||||
write partial outputs, and note it in the run summary.
|
||||
2
.github/workflows/expected_cve_count
vendored
2
.github/workflows/expected_cve_count
vendored
@@ -1 +1 @@
|
||||
31
|
||||
32
|
||||
|
||||
129
.github/workflows/vuln-scan.yml
vendored
Normal file
129
.github/workflows/vuln-scan.yml
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
name: Online search for vulns
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '42 8 * * *'
|
||||
workflow_dispatch: {} # allow manual trigger
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read # needed to list/download previous run artifacts
|
||||
id-token: write # needed to mint OIDC token
|
||||
|
||||
concurrency:
|
||||
group: vuln-scan
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout repository (for grep-based dedup against existing checks)
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
# ---- Load previous state ---------------------------------------------
|
||||
# Find the most recent successful run of THIS workflow (other than the
|
||||
# current one) and pull its `vuln-scan-state` artifact. On the very
|
||||
# first run there will be none — that's fine, we start empty.
|
||||
- name: Find previous successful run id
|
||||
id: prev
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
run_id=$(gh run list \
|
||||
--workflow="${{ github.workflow }}" \
|
||||
--status=success \
|
||||
--limit 1 \
|
||||
--json databaseId \
|
||||
--jq '.[0].databaseId // empty')
|
||||
echo "run_id=${run_id}" >> "$GITHUB_OUTPUT"
|
||||
if [ -n "$run_id" ]; then
|
||||
echo "Found previous successful run: $run_id"
|
||||
else
|
||||
echo "No previous successful run — starting from empty state."
|
||||
fi
|
||||
|
||||
- name: Download previous state artifact
|
||||
if: steps.prev.outputs.run_id != ''
|
||||
uses: actions/download-artifact@v4
|
||||
continue-on-error: true # tolerate retention expiry
|
||||
with:
|
||||
name: vuln-scan-state
|
||||
path: state/
|
||||
run-id: ${{ steps.prev.outputs.run_id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Ensure state file exists
|
||||
run: |
|
||||
mkdir -p state
|
||||
if [ ! -f state/seen.json ]; then
|
||||
echo '{"last_run": null, "seen": {}}' > state/seen.json
|
||||
echo "Initialized empty state."
|
||||
fi
|
||||
echo "State size: $(wc -c < state/seen.json) bytes"
|
||||
|
||||
# ---- Run the scan ----------------------------------------------------
|
||||
# Runs Claude Code against daily_vuln_scan_prompt.md.
|
||||
# That prompt file fully specifies: sources to poll, how to read
|
||||
# state/seen.json, the 25-hour window, the output files to write,
|
||||
# and how to rewrite state/seen.json at the end of the run.
|
||||
- name: Research for online mentions of new vulns
|
||||
id: scan
|
||||
uses: anthropics/claude-code-action@v1
|
||||
env:
|
||||
SCAN_DATE: ${{ github.run_started_at }}
|
||||
with:
|
||||
claude_args: |
|
||||
--model claude-opus-4-7 --allowedTools "Read,Write,Edit,Bash,Grep,Glob,WebFetch"
|
||||
prompt: |
|
||||
Read the full task instructions from .github/workflows/daily_vuln_scan_prompt.md and execute them end-to-end. That file fully specifies: sources to poll, how to read and update state/seen.json, the 25-hour window, which rss_YYYY-MM-DD_*.md files to write, and the run guardrails. Use $SCAN_DATE (env var) as "now" for time-window decisions.
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
|
||||
- name: Upload Claude execution log
|
||||
if: ${{ always() && steps.scan.outputs.execution_file != '' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: claude-execution-log-${{ github.run_id }}
|
||||
path: ${{ steps.scan.outputs.execution_file }}
|
||||
retention-days: 30
|
||||
if-no-files-found: warn
|
||||
|
||||
# ---- Persist outputs -------------------------------------------------
|
||||
- name: Prune state (keep only entries from the last 30 days)
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json, datetime, pathlib
|
||||
p = pathlib.Path("state/seen.json")
|
||||
data = json.loads(p.read_text())
|
||||
cutoff = (datetime.datetime.utcnow() - datetime.timedelta(days=30)).isoformat()
|
||||
before = len(data.get("seen", {}))
|
||||
data["seen"] = {
|
||||
k: v for k, v in data.get("seen", {}).items()
|
||||
if v.get("seen_at", "9999") >= cutoff
|
||||
}
|
||||
after = len(data["seen"])
|
||||
p.write_text(json.dumps(data, indent=2, sort_keys=True))
|
||||
print(f"Pruned state: {before} -> {after} entries")
|
||||
PY
|
||||
|
||||
- name: Upload new state artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vuln-scan-state
|
||||
path: state/seen.json
|
||||
retention-days: 90
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload daily report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vuln-scan-report-${{ github.run_id }}
|
||||
path: rss_*.md
|
||||
retention-days: 90
|
||||
if-no-files-found: warn
|
||||
@@ -38,6 +38,7 @@ CVE | Name | Aliases
|
||||
[CVE-2024-36357](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36357) | Transient Scheduler Attack, L1 | TSA-L1
|
||||
[CVE-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-2025-54505](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54505) | AMD Zen1 Floating-Point Divider Stale Data Leak | FPDSS
|
||||
|
||||
## Am I at risk?
|
||||
|
||||
@@ -77,6 +78,7 @@ CVE-2024-36350 (TSA-SQ) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel
|
||||
CVE-2024-36357 (TSA-L1) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
CVE-2025-40300 (VMScape) | ✅ | ✅ | 💥 | ✅ | Kernel update (IBPB on VM-exit)
|
||||
CVE-2024-45332 (BPI) | 💥 | ✅ | 💥 | ✅ | Microcode update
|
||||
CVE-2025-54505 (FPDSS) | 💥 | 💥 | 💥 | 💥 | Kernel update
|
||||
|
||||
> 💥 Data can be leaked across this boundary.
|
||||
|
||||
@@ -207,6 +209,10 @@ After a guest VM exits to the host, stale branch predictions from the guest can
|
||||
|
||||
A race condition in the branch predictor update mechanism of Intel processors (Coffee Lake through Raptor Lake, plus some server and Atom parts) allows user-space branch predictions to briefly influence kernel-space speculative execution, undermining eIBRS and IBPB protections. This means systems relying solely on eIBRS for Spectre V2 mitigation may not be fully protected without the microcode fix. Mitigation requires a microcode update (intel-microcode 20250512+) that fixes the asynchronous branch predictor update timing so that eIBRS and IBPB work as originally intended. No kernel changes are required. Performance impact is negligible.
|
||||
|
||||
**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>
|
||||
|
||||
## Unsupported CVEs
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#
|
||||
# Stephane Lesimple
|
||||
#
|
||||
VERSION='26.32.0410743'
|
||||
VERSION='26.33.0418638'
|
||||
|
||||
# --- Common paths and basedirs ---
|
||||
readonly VULN_SYSFS_BASE="/sys/devices/system/cpu/vulnerabilities"
|
||||
@@ -208,6 +208,12 @@ g_smc_cpu_info_line=''
|
||||
|
||||
# CVE Registry: single source of truth for all CVE metadata.
|
||||
# Fields: cve_id|json_key_name|affected_var_suffix|complete_name_and_aliases
|
||||
#
|
||||
# Two ranges of placeholder IDs are reserved when no real CVE applies:
|
||||
# CVE-0000-NNNN: permanent placeholder for supplementary checks (--extra only)
|
||||
# that will never receive a real CVE (e.g. SLS, compile-time hardening).
|
||||
# CVE-9999-NNNN: temporary placeholder for real vulnerabilities awaiting CVE
|
||||
# assignment. Rename across the codebase once the real CVE is issued.
|
||||
readonly CVE_REGISTRY='
|
||||
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
|
||||
@@ -241,6 +247,7 @@ CVE-2025-40300|VMSCAPE|vmscape|VMScape, VM-exit stale branch prediction
|
||||
CVE-2023-28746|RFDS|rfds|Register File Data Sampling (RFDS)
|
||||
CVE-2024-45332|BPI|bpi|Branch Privilege Injection (BPI)
|
||||
CVE-0000-0001|SLS|sls|Straight-Line Speculation (SLS)
|
||||
CVE-2025-54505|FPDSS|fpdss|FPDSS, AMD Zen1 Floating-Point Divider Stale Data Leak
|
||||
'
|
||||
|
||||
# Derive the supported CVE list from the registry
|
||||
@@ -738,8 +745,9 @@ is_cpu_affected() {
|
||||
affected_srbds=''
|
||||
affected_mmio=''
|
||||
affected_sls=''
|
||||
# DIV0, Zenbleed and Inception are all AMD specific, look for "is_amd" below:
|
||||
# DIV0, FPDSS, Zenbleed and Inception are all AMD specific, look for "is_amd" below:
|
||||
_set_immune div0
|
||||
_set_immune fpdss
|
||||
_set_immune zenbleed
|
||||
_set_immune inception
|
||||
# TSA is AMD specific (Zen 3/4), look for "is_amd" below:
|
||||
@@ -1237,13 +1245,23 @@ is_cpu_affected() {
|
||||
fi
|
||||
_set_immune variantl1tf
|
||||
|
||||
# DIV0 (Zen1 only)
|
||||
# DIV0 (Zen1/Zen+)
|
||||
# 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
|
||||
# All Zen1 CPUs are family 0x17, models 0x00-0x2f and 0x50-0x5f
|
||||
# bfff3c6692ce (v6.8): moved to init_amd_zen1(), unconditional for all ZEN1-flagged CPUs
|
||||
# The kernel's X86_FEATURE_ZEN1 covers family 0x17 models 0x00-0x2f and 0x50-0x5f,
|
||||
# which spans both Zen1 (Summit Ridge, Naples, Raven Ridge, Snowy Owl) and Zen+
|
||||
# (Pinnacle Ridge, Picasso, Dali, Colfax) products -- all using the same divider silicon.
|
||||
amd_legacy_erratum "$(amd_model_range 0x17 0x00 0x0 0x2f 0xf)" && _set_vuln div0
|
||||
amd_legacy_erratum "$(amd_model_range 0x17 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
|
||||
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
|
||||
@@ -1453,7 +1471,7 @@ is_cpu_affected() {
|
||||
pr_debug "is_cpu_affected: final results: variant1=$affected_variant1 variant2=$affected_variant2 variant3=$affected_variant3 variant3a=$affected_variant3a"
|
||||
pr_debug "is_cpu_affected: final results: 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: div0=$affected_div0 zenbleed=$affected_zenbleed inception=$affected_inception retbleed=$affected_retbleed tsa=$affected_tsa downfall=$affected_downfall reptar=$affected_reptar rfds=$affected_rfds its=$affected_its"
|
||||
pr_debug "is_cpu_affected: final results: div0=$affected_div0 fpdss=$affected_fpdss zenbleed=$affected_zenbleed inception=$affected_inception retbleed=$affected_retbleed tsa=$affected_tsa downfall=$affected_downfall reptar=$affected_reptar rfds=$affected_rfds its=$affected_its"
|
||||
pr_debug "is_cpu_affected: final results: vmscape=$affected_vmscape bpi=$affected_bpi sls=$affected_sls mmio=$affected_mmio"
|
||||
}
|
||||
affected_variantl1tf_sgx="$affected_variantl1tf"
|
||||
@@ -2149,7 +2167,7 @@ while [ -n "${1:-}" ]; do
|
||||
case "$2" in
|
||||
help)
|
||||
echo "The following parameters are supported for --variant (can be used multiple times):"
|
||||
echo "1, 2, 3, 3a, 4, msbds, mfbds, mlpds, mdsum, l1tf, taa, mcepsc, srbds, mmio, sbdr, sbds, drpw, div0, zenbleed, downfall, retbleed, inception, reptar, rfds, tsa, tsa-sq, tsa-l1, its, vmscape, bpi, sls"
|
||||
echo "1, 2, 3, 3a, 4, msbds, mfbds, mlpds, mdsum, l1tf, taa, mcepsc, srbds, mmio, sbdr, sbds, drpw, div0, fpdss, zenbleed, downfall, retbleed, inception, reptar, rfds, tsa, tsa-sq, tsa-l1, its, vmscape, bpi, sls"
|
||||
exit 0
|
||||
;;
|
||||
1)
|
||||
@@ -2224,6 +2242,10 @@ while [ -n "${1:-}" ]; do
|
||||
opt_cve_list="$opt_cve_list CVE-2023-20588"
|
||||
opt_cve_all=0
|
||||
;;
|
||||
fpdss)
|
||||
opt_cve_list="$opt_cve_list CVE-2025-54505"
|
||||
opt_cve_all=0
|
||||
;;
|
||||
zenbleed)
|
||||
opt_cve_list="$opt_cve_list CVE-2023-20593"
|
||||
opt_cve_all=0
|
||||
@@ -11980,6 +12002,160 @@ check_CVE_2025_40300_bsd() {
|
||||
fi
|
||||
}
|
||||
|
||||
# >>>>>> vulns/CVE-2025-54505.sh <<<<<<
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# >>>>>> main.sh <<<<<<
|
||||
|
||||
# vim: set ts=4 sw=4 sts=4 et:
|
||||
@@ -12375,7 +12551,7 @@ exit 0 # ok
|
||||
# with X being either I for Intel, or A for AMD
|
||||
# When the date is unknown it defaults to 20000101
|
||||
|
||||
# %%% MCEDB v349+i20260227+615b
|
||||
# %%% MCEDB v349+i20260227+1cce
|
||||
# I,0x00000611,0xFF,0x00000B27,19961218
|
||||
# I,0x00000612,0xFF,0x000000C6,19961210
|
||||
# I,0x00000616,0xFF,0x000000C6,19961210
|
||||
|
||||
Reference in New Issue
Block a user