mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-06-16 11:33:01 +02:00
Compare commits
74 Commits
master
..
50845adbfb
| Author | SHA1 | Date | |
|---|---|---|---|
| 50845adbfb | |||
| 7eaa794980 | |||
| 7e5eee74ac | |||
| 9bef6ec533 | |||
| f587d9355e | |||
| 83be8fd544 | |||
| 9383287fc6 | |||
| a2823830a6 | |||
| 6212de226a | |||
| f8873048fc | |||
| 463e33d61c | |||
| 4d1af90420 | |||
| e8a3c7d7f5 | |||
| 8ae598802c | |||
| 48a4c0e49c | |||
| 1557bbee42 | |||
| 4530f39fae | |||
| d247733496 | |||
| fc66ee567a | |||
| 072b98cefd | |||
| bceb62f982 | |||
| aacdd35c57 | |||
| c0a389b086 | |||
| 726f9e54f5 | |||
| 11210ab772 | |||
| 624aef4a46 | |||
| b6a7ee2345 | |||
| 5698711b3d | |||
| e0f9aeab81 | |||
| 2f550ba8cd | |||
| 3f60773ec4 | |||
| acaf3b684f | |||
| 0ec51090ae | |||
| e9cb988409 | |||
| c147f3f7d4 | |||
| 065f19e313 | |||
| 1214e63687 | |||
| 67be7eb116 | |||
| b4db134e49 | |||
| d7cd9e8b6b | |||
| a4c3900ef0 | |||
| 1d00acbc9a | |||
| 90a8a3057c | |||
| 40b7ae9098 | |||
| 27ac93dd39 | |||
| dab7bebd3c | |||
| 8f76537159 | |||
| fd7083cb08 | |||
| 8ef4c71d36 | |||
| 240d6db210 | |||
| fbfdb89e7a | |||
| 5c571bacc6 | |||
| 6f8112c700 | |||
| f46c743cad | |||
| 33bdd0688d | |||
| 7f87ade3fe | |||
| e2d4d14e14 | |||
| ddf2f2c723 | |||
| fe376887ab | |||
| 7b41bcca2b | |||
| 151dd12e3e | |||
| 15ea90f312 | |||
| 5fd6a20ebb | |||
| e7df6a3e30 | |||
| ba24551c56 | |||
| 7c2699c01a | |||
| 6663b6422e | |||
| fe55c70658 | |||
| d0822e1f9d | |||
| 10e5b5749e | |||
| 4f7f83a40e | |||
| 4bbbd71564 | |||
| c174a8b754 | |||
| 0f36203b5f |
@@ -7,26 +7,21 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
autoupdate:
|
autoupdate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
ref: source
|
|
||||||
- name: Install prerequisites
|
- name: Install prerequisites
|
||||||
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends iucode-tool sqlite3 unzip shfmt
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends iucode-tool sqlite3 unzip
|
||||||
- name: Update microcode versions
|
- name: Update microcode versions
|
||||||
run: ./scripts/update_mcedb.sh
|
run: ./spectre-meltdown-checker.sh --update-builtin-fwdb
|
||||||
- name: Update Intel models
|
|
||||||
run: ./scripts/update_intel_models.sh
|
|
||||||
- name: Check git diff
|
- name: Check git diff
|
||||||
id: diff
|
id: diff
|
||||||
run: |
|
run: |
|
||||||
echo change="$(git diff | awk '/MCEDB/ { if(V) { print V" to "$4; exit } else { V=$4 } }')" >> "$GITHUB_OUTPUT"
|
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 | grep -cE -- '^\+# [AI],')" >> "$GITHUB_OUTPUT"
|
echo nbdiff="$(git diff spectre-meltdown-checker.sh | grep -cE -- '^\+# [AI],')" >> "$GITHUB_OUTPUT"
|
||||||
git diff
|
git diff
|
||||||
cat "$GITHUB_OUTPUT"
|
cat "$GITHUB_OUTPUT"
|
||||||
- name: Create Pull Request if needed
|
- name: Create Pull Request if needed
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -8,7 +8,7 @@ on:
|
|||||||
action:
|
action:
|
||||||
description: "dry-run"
|
description: "dry-run"
|
||||||
required: true
|
required: true
|
||||||
default: "apply"
|
default: "dryrun"
|
||||||
type: choice
|
type: choice
|
||||||
options:
|
options:
|
||||||
- dryrun
|
- dryrun
|
||||||
@@ -30,7 +30,4 @@ jobs:
|
|||||||
days-before-close: 7
|
days-before-close: 7
|
||||||
stale-issue-label: stale
|
stale-issue-label: stale
|
||||||
remove-stale-when-updated: true
|
remove-stale-when-updated: true
|
||||||
close-issue-reason: completed
|
|
||||||
stale-issue-message: "If there are no further comments or activity on this issue, it'll be closed automatically in 7 days."
|
|
||||||
close-issue-message: "Automatically closing this issue due to inactivity, don't hesitate to open a new issue if needed."
|
|
||||||
debug-only: ${{ case(inputs.action == 'dryrun', true, false) }}
|
debug-only: ${{ case(inputs.action == 'dryrun', true, false) }}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
name: Online search for vulns
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '42 8 * * *'
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
model:
|
|
||||||
description: 'Claude model to use (cron runs default to Sonnet)'
|
|
||||||
required: false
|
|
||||||
type: choice
|
|
||||||
default: claude-sonnet-4-6
|
|
||||||
options:
|
|
||||||
- claude-sonnet-4-6
|
|
||||||
- claude-opus-4-7
|
|
||||||
- claude-haiku-4-5-20251001
|
|
||||||
window_hours:
|
|
||||||
description: 'Lookback window in hours (cron runs use 25)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: '25'
|
|
||||||
reconsider_age_days:
|
|
||||||
description: 'Only reconsider backlog entries last reviewed ≥ N days ago (0 = all, default 7)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: '7'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
actions: read # needed to list/download previous run artifacts
|
|
||||||
id-token: write # needed by claude-code-action for OIDC auth
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: vuln-watch
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
watch:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 20
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# The scripts driving this workflow live on the `vuln-watch` branch so
|
|
||||||
# they don't clutter master (which is what ships to production). The
|
|
||||||
# workflow file itself MUST stay on the default branch, as GitHub only
|
|
||||||
# honors `schedule:` triggers on the default branch.
|
|
||||||
- name: Checkout vuln-watch branch (scripts + prompt)
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
ref: vuln-watch
|
|
||||||
fetch-depth: 1
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: '3.12'
|
|
||||||
|
|
||||||
- name: Install Python dependencies
|
|
||||||
run: python -m pip install --quiet feedparser
|
|
||||||
|
|
||||||
# ---- Load previous state ---------------------------------------------
|
|
||||||
# Find the most recent successful run of THIS workflow (other than the
|
|
||||||
# current one) and pull its `vuln-watch-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@v8
|
|
||||||
continue-on-error: true # tolerate retention expiry
|
|
||||||
with:
|
|
||||||
name: vuln-watch-state
|
|
||||||
path: state/
|
|
||||||
run-id: ${{ steps.prev.outputs.run_id }}
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
# ---- Fetch + diff (token-free; runs every time) ---------------------
|
|
||||||
# Performs conditional GETs (ETag / If-Modified-Since) against every
|
|
||||||
# source, parses RSS/Atom/HTML, dedups against state.seen + state.aliases,
|
|
||||||
# applies the time-window filter, and emits new_items.json.
|
|
||||||
# Updates state.sources (HTTP cache metadata + per-source high-water
|
|
||||||
# marks) in place so the cache survives even when Claude doesn't run.
|
|
||||||
- name: Fetch + diff all sources
|
|
||||||
id: diff
|
|
||||||
env:
|
|
||||||
SCAN_DATE: ${{ github.run_started_at }}
|
|
||||||
# Cron runs have no `inputs` context, so the fallback kicks in.
|
|
||||||
WINDOW_HOURS: ${{ inputs.window_hours || '25' }}
|
|
||||||
RECONSIDER_AGE_DAYS: ${{ inputs.reconsider_age_days || '7' }}
|
|
||||||
run: python -m scripts.vuln_watch.fetch_and_diff
|
|
||||||
|
|
||||||
# ---- Fetch checker code so Claude can grep it for coverage ---------
|
|
||||||
# The orphan vuln-watch branch has none of the actual checker code,
|
|
||||||
# so we pull the `test` branch (the dev branch where coded-but-
|
|
||||||
# unreleased CVE checks live) into ./checker/. The prompt tells
|
|
||||||
# Claude this is the canonical source of truth for "is CVE-X already
|
|
||||||
# implemented?". Only fetched on days with something to classify.
|
|
||||||
- name: Checkout checker code (test branch) for coverage grep
|
|
||||||
if: steps.diff.outputs.new_count != '0' || steps.diff.outputs.reconsider_count != '0'
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
ref: test
|
|
||||||
path: checker
|
|
||||||
fetch-depth: 1
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
# ---- Classify new items with Claude (skipped when nothing is new) ---
|
|
||||||
# Model selection: a manual workflow_dispatch run picks from a dropdown
|
|
||||||
# (defaulting to Sonnet). Scheduled cron runs have no `inputs` context,
|
|
||||||
# so the `|| 'claude-sonnet-4-6'` fallback kicks in — cron always uses
|
|
||||||
# Sonnet to keep the daily cost floor low.
|
|
||||||
- name: Run classifier with Claude
|
|
||||||
id: classify
|
|
||||||
if: steps.diff.outputs.new_count != '0' || steps.diff.outputs.reconsider_count != '0'
|
|
||||||
uses: anthropics/claude-code-action@v1
|
|
||||||
env:
|
|
||||||
SCAN_DATE: ${{ github.run_started_at }}
|
|
||||||
with:
|
|
||||||
prompt: |
|
|
||||||
Read the full task instructions from scripts/daily_vuln_watch_prompt.md
|
|
||||||
and execute them end-to-end. Your input is new_items.json (already
|
|
||||||
deduped, windowed, and pre-filtered — do NOT re-fetch sources).
|
|
||||||
Write the three watch_${TODAY}_*.md files and classifications.json.
|
|
||||||
Use $SCAN_DATE as the canonical timestamp.
|
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
||||||
# model + tool allowlist pass through claude_args (v1 dropped the
|
|
||||||
# dedicated `model:` and `allowed_tools:` inputs). Job-level
|
|
||||||
# `timeout-minutes: 20` above bounds total runtime.
|
|
||||||
claude_args: |
|
|
||||||
--model ${{ inputs.model || 'claude-sonnet-4-6' }}
|
|
||||||
--allowedTools "Read,Write,Edit,Bash,Grep,Glob,WebFetch"
|
|
||||||
|
|
||||||
- name: Upload Claude execution log
|
|
||||||
if: ${{ always() && steps.classify.outputs.execution_file != '' }}
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: claude-execution-log-${{ github.run_id }}
|
|
||||||
path: ${{ steps.classify.outputs.execution_file }}
|
|
||||||
retention-days: 30
|
|
||||||
if-no-files-found: warn
|
|
||||||
|
|
||||||
# ---- Merge classifications back into state --------------------------
|
|
||||||
# Also writes stub watch_*.md files if the classify step was skipped, so
|
|
||||||
# the report artifact is consistent across runs.
|
|
||||||
- name: Merge classifications into state
|
|
||||||
if: always()
|
|
||||||
env:
|
|
||||||
SCAN_DATE: ${{ github.run_started_at }}
|
|
||||||
run: python -m scripts.vuln_watch.merge_state
|
|
||||||
|
|
||||||
- name: Upload new state artifact
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: vuln-watch-state
|
|
||||||
path: state/seen.json
|
|
||||||
retention-days: 90
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: Upload daily report
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: vuln-watch-report-${{ github.run_id }}
|
|
||||||
path: |
|
|
||||||
watch_*.md
|
|
||||||
current_toimplement.md
|
|
||||||
current_tocheck.md
|
|
||||||
new_items.json
|
|
||||||
classifications.json
|
|
||||||
retention-days: 90
|
|
||||||
if-no-files-found: warn
|
|
||||||
@@ -40,14 +40,6 @@ CVE | Name | Aliases
|
|||||||
[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
|
[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?
|
||||||
|
|
||||||
Depending on your situation, the table below answers whether an attacker in a given position can extract data from a given target.
|
Depending on your situation, the table below answers whether an attacker in a given position can extract data from a given target.
|
||||||
@@ -280,23 +272,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
|
||||||
|
|
||||||
|
|||||||
@@ -307,13 +307,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.
|
|
||||||
|
|||||||
+3
-5
@@ -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
|
||||||
|
|||||||
@@ -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)" }
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-7
@@ -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
|
||||||
|
|||||||
+16
-46
@@ -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:**
|
||||||
@@ -376,15 +352,9 @@ queries. CVE checks that rely on hardware capability detection (`cap_*` flags,
|
|||||||
MSR reads) will report `unknown` status. `mode="no-hw"` in `smc_build_info`
|
MSR reads) will report `unknown` status. `mode="no-hw"` in `smc_build_info`
|
||||||
signals this.
|
signals this.
|
||||||
|
|
||||||
**Cross-arch inspection (`--arch-prefix`)**
|
|
||||||
When a cross-arch toolchain prefix is passed, the script suppresses the host
|
|
||||||
CPU metadata so it does not get mixed with data from a different-arch target
|
|
||||||
kernel: `smc_cpu_info` is not emitted, the same as under `--no-hw`.
|
|
||||||
|
|
||||||
**Hardware-only mode (`--hw-only`)**
|
**Hardware-only mode (`--hw-only`)**
|
||||||
Only hardware detection is performed; CVE checks are skipped. `smc_cpu_info`
|
Only hardware detection is performed; CVE checks are skipped. `smc_cpu_info`
|
||||||
is emitted but no `smc_vulnerability_status` metrics appear (and
|
is emitted but no `smc_vuln` metrics appear. `mode="hw-only"` in
|
||||||
`smc_vulnerable_count` / `smc_unknown_count` are `0`). `mode="hw-only"` in
|
|
||||||
`smc_build_info` signals this.
|
`smc_build_info` signals this.
|
||||||
|
|
||||||
**`--sysfs-only`**
|
**`--sysfs-only`**
|
||||||
|
|||||||
+124
-706
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user