core/host: add meltdown_mitigation passthrough + migrate entrybleed

The kpti_enabled bool in struct skeletonkey_host flattens three
distinct sysfs states into one bit:

  /sys/devices/system/cpu/vulnerabilities/meltdown content:
    - 'Not affected'      → CPU is Meltdown-immune; KPTI off; EntryBleed
                            doesn't apply (verdict: OK)
    - 'Mitigation: PTI'   → KPTI on (verdict: VULNERABLE)
    - 'Vulnerable'        → KPTI off but CPU not hardened (rare;
                            verdict: VULNERABLE conservatively)
    - file unreadable     → unknown (verdict: VULNERABLE conservatively)

kpti_enabled=true only captures 'Mitigation: PTI'; kpti_enabled=false
collapses 'Not affected', 'Vulnerable', and 'unreadable' into one
indistinguishable case. That meant entrybleed_detect() had to
re-open the sysfs file to recover the raw string.

Fix by also stashing the raw first line in
ctx->host->meltdown_mitigation[64]. kpti_enabled stays for callers
that only need the simple bool; new code that needs the nuance reads
the string. populate happens once at startup, like every other host
field.

entrybleed migration:
  - reads ctx->host->meltdown_mitigation instead of opening sysfs
  - removes the file-local read_first_line() helper (now dead code)
  - same three-way verdict logic, but driven by a const char *
    instead of a fresh fopen() each detect()

Test coverage:
  - 3 new test rows on x86_64 fingerprints:
      empty mitigation       → VULNERABLE (conservative)
      'Not affected'         → OK
      'Mitigation: PTI'      → VULNERABLE
  - 1 stub-path test row on non-x86_64 fingerprints (PRECOND_FAIL)
  - registry coverage report: 30/31 modules now have direct tests
    (up from 29/31; copy_fail is the only remaining untested module)

Verification:
  - macOS: 33 kernel_range + 1 entrybleed-stub = 34 passes, 0 fails
  - Linux (docker gcc:latest): 33 kernel_range + 54 detect = 87
    passes, 0 fails. Up from 83 last commit.
This commit is contained in:
2026-05-23 01:14:38 -04:00
parent e2fef41667
commit 60d22eb4f6
4 changed files with 68 additions and 23 deletions
+11 -1
View File
@@ -190,6 +190,7 @@ static void populate_caps(struct skeletonkey_host *h)
h->apparmor_restrict_userns = false;
h->unprivileged_bpf_disabled = false;
h->kpti_enabled = false;
h->meltdown_mitigation[0] = '\0';
h->kernel_lockdown_active = false;
h->selinux_enforcing = false;
h->yama_ptrace_restricted = false;
@@ -208,8 +209,17 @@ static void populate_caps(struct skeletonkey_host *h)
h->yama_ptrace_restricted = (v > 0);
char buf[256];
if (read_first_line("/sys/devices/system/cpu/vulnerabilities/meltdown", buf, sizeof buf))
if (read_first_line("/sys/devices/system/cpu/vulnerabilities/meltdown", buf, sizeof buf)) {
h->kpti_enabled = (strstr(buf, "Mitigation: PTI") != NULL);
/* Stash the raw value so modules that need richer matching
* (e.g. entrybleed distinguishing "Not affected" CPUs from
* "Vulnerable" / "Mitigation: PTI") don't re-read sysfs. */
size_t L = strlen(buf);
if (L >= sizeof h->meltdown_mitigation)
L = sizeof h->meltdown_mitigation - 1;
memcpy(h->meltdown_mitigation, buf, L);
h->meltdown_mitigation[L] = '\0';
}
/* /sys/kernel/security/lockdown format: "[none] integrity confidentiality"
* — whichever level is bracketed is the active one. */