β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4779

corecstat attaches on any Intel CPU outside family 06h β€” probe()/attach() model whitelist has no else-return, so the driver matches (e.g.) family-0x0F Pentium 4 and runs with an unassigned sc_version

Summary

Neither probe nor attach has an else-return for cpu_family != 0x06 - any non-06h Intel CPU attaches with sc_version=0 (Nehalem treatment). Guest-reproduced on stock QEMU CPU (family 0x0F): 6 devices attach, 17 rdmsr_safe rejections, phantom sensordev, 1Hz refresh per cpu; no panic (rdmsr_safe gating saved it - the DF-4735 family is defended here). Family-gate fix validated (attaches nothing).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4779 Β· 9 files
FileTypeDescriptionSize
README.md β€” 3.2 KB ↓ raw
VERDICT.md β€” 3.0 KB ↓ raw
build.sh β€” 66 B view raw
run.sh β€” 90 B view raw
build.log β€” 1.1 KB view raw
run.log β€” 4.0 KB view raw
env.txt β€” 745 B view raw
fix.diff β€” 703 B view raw
verdict.json β€” 2.9 KB view raw

DF-4779 β€” corecstat attaches on any Intel CPU outside family 06h (missing return ENXIO for cpu_family != 0x06)

File: sys/dev/powermng/corecstat/corecstat.c Severity: Info (functional/robustness β€” no memory-safety impact) Β· Confidence: certain Bucket: base:powermng

What the bug is

Both corecstat_probe() (corecstat.c:183-236) and corecstat_attach() (corecstat.c:259-324) gate the model whitelist on if (cpu_family == 0x06) { switch (cpu_model) { ... default: return (ENXIO); } } β€” but there is no else branch. For an Intel CPU with any family other than 06h (e.g. family 0x0F Pentium 4 / NetBurst Xeon, family 05h), the whitelist is skipped entirely and corecstat_probe() returns BUS_PROBE_GENERIC β€” a match β€” and corecstat_attach() proceeds with sc->sc_version never assigned.

The driver's contract (header comment, corecstat.c:27-31) is "Nehalem and later Core CPUs" β€” all of which are family 06h. corecstat_identify() gates on cpu_vendor_id == CPU_VENDOR_INTEL (corecstat.c:160) but never on family.

Why it is memory-safe (why this is Info, not higher)

  • The softc is allocated M_ZERO by newbus (sys/kern/subr_bus.c:1953-1954), so the unassigned sc_version is 0 β†’ Nehalem/Westmere treatment. Even a garbage version could not overflow: sc_core_sens[3] takes at most 3 sensors for any version value (corecstat.c:460-471) and sc_pkg_sens is kmalloc'd for 7 with at most 7 added (corecstat.c:435-456).
  • Every MSR read that creates a sensor goes through corecstat_try() β†’ rdmsr_safe() (corecstat.c:594-603), so the DF-4735 raw-rdmsr-#GP family cannot fire here. The only raw rdmsr() calls (corecstat.c:531, 549) execute solely for sensors whose MSR already passed rdmsr_safe at attach.

What actually happens (guest-reproduced)

On the QEMU/KVM guest (vendor=GenuineIntel, family 0x0F, model 0x0B β€” "QEMU Virtual CPU version 2.5+"), loading the stock, unmodified corecstat.ko:

  • corecstat0..corecstat5 all attach ("<CPU Package C-State residency counters> on cpuN")
  • every residency MSR is gracefully rejected by rdmsr_safe β†’ 17 console lines "msr node0 ... not available" (the version-0 Nehalem set: core C3/C6 everywhere, plus PC3/PC6/PC7 on the chip-representative cpu5)
  • a phantom empty sensordev cpu_node0 is installed and hw.sensors.dev_idmax bumps 6 β†’ 7 with zero sensors in it
  • the 1 Hz refresh task is registered on every cpu with zero sensors to refresh
  • kldunload corecstat is clean.

No panic, no corruption β€” pure wrong-attach + console spam + useless per-cpu sensor tasks on exactly the silicon the driver must reject (Pentium 4-class family 0x0F, etc.).

Reproduce

# on the DragonFly guest (as root), stock kernel, stock cpu (family 0x0F):
sh build.sh          # builds stock corecstat.ko from pristine /usr/src source
sh run.sh            # kldload, show dmesg + hw.sensors.dev_idmax, kldunload
# expected: 6x attach lines, 17x "msr ... not available", dev_idmax 6->7->6, no panic

Fix

fix.diff adds the missing family gate to both probe and attach (validated on the guest: with the fix, kldload produces no devices at all and hw.sensors.dev_idmax stays 6).

VERDICT.md
↓ download raw

VERDICT β€” DF-4779

Reproduced? YES (2 runs, plus fix validation)

On the stock QEMU/KVM guest β€” CPU vendor GenuineIntel, family 0x0F, model 0x0B (not family 06h) β€” the stock, unmodified corecstat.ko (built from pristine /usr/src/sys/dev/powermng/corecstat/corecstat.c, -Werror clean):

  1. All six corecstatN devices attach (corecstat0..5: <CPU Package C-State residency counters> on cpuN). Root cause: corecstat_probe() wraps its model whitelist in if (cpu_family == 0x06) { ... default: return (ENXIO); } with no else-return (corecstat.c:183-236) β†’ any Intel family β‰  06h probes as BUS_PROBE_GENERIC. corecstat_attach() has the identical missing gate (corecstat.c:259-324).
  2. sc->sc_version is never assigned on this path; newbus zero-allocation (sys/kern/subr_bus.c:1953-1954) makes it 0 β†’ the driver probes the Nehalem MSR set (core C3 0x3fc / C6 0x3fd on every cpu; PC3 0x3f8 / PC6 0x3f9 / PC7 0x3fa on the chip-representative cpu5) β€” every read gracefully rejected by rdmsr_safe (corecstat.c:598), 17 msr ... not available console lines.
  3. A phantom empty sensordev cpu_node0 is installed: hw.sensors.dev_idmax 6 β†’ 7 with zero sensors; per-cpu 1 Hz refresh tasks registered with zero sensors.
  4. kldunload clean; no panic anywhere β€” the DF-4735 raw-rdmsr-#GP family cannot fire through this driver because every sensor-creating MSR read is rdmsr_safe-gated (corecstat.c:594-603) and the only raw rdmsr() calls (corecstat.c:531, 549) execute solely for try-validated MSRs.

Impact: none (functional/robustness)

No memory corruption is possible even with a garbage sc_version: sc_core_sens[3] receives at most 3 sensors for any version value (corecstat.c:460-471) and sc_pkg_sens is sized 7 with at most 7 added (corecstat.c:435-456). On real family-0x0F/05h Intel silicon the observable effect is identical to the guest: wrong attach, console spam, a useless sensor task per cpu, a phantom sensordev per chip.

Exploit chain: (none β€” not a memory-safety bug)

Fix validation: FIXED

fix.diff adds the family gate to both probe and attach. Guest-validated: with the fix, kldload attaches nothing (no corecstatN: lines, no msr ... not available lines, hw.sensors.dev_idmax stays 6), unload clean. Baseline (unfixed) attaches 6 devices and bumps dev_idmax to 7 β€” the previously-observed wrong behavior is gone.

Files

  • run.log β€” two verbatim guest runs + fix-validation capture
  • build.log β€” module build (stock source, -Werror, clean)
  • env.txt β€” guest kernel/CPUID state
  • fix.diff β€” the family gate

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

With fix.diff (family gate in probe+attach) applied to the module source, the same kldload on the same family-0x0F guest attaches zero devices: no corecstatN lines, no MSR-probe console spam, hw.sensors.dev_idmax remains 6 (baseline attached 6 devices and bumped it to 7). Wrong-attach behavior eliminated.

run.log FIX VALIDATION block: '2' (both sites patched), BUILD_OK, KLDLOAD_RC=0, dev_idmax 6 before and after load (no phantom sensordev), UNLOAD_OK.
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #0 (X86_64_GENERIC) + fixed corecstat.kld module

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log: 'corecstat0..5: <CPU Package C-State residency counters> on cpuN' on family 0x0F + 17x 'msr ... not available' + hw.sensors.dev_idmax 6->7->6; VERDICT.md path:line analysis (corecstat.c:183-236, 259-324, subr_bus.c:1953)

PoC changes

No trigger program needed: the stock module kldload on the stock guest CPU is the trigger. build.sh/run.sh captured verbatim.

Verified recommended fix

Reject cpu_family != 0x06 in both corecstat_probe() and corecstat_attach() (see fix.diff).

Verdict

Reproduced on the stock QEMU guest (Intel vendor, family 0x0F): the missing family-06h gate in corecstat_probe()/corecstat_attach() lets corecstat attach all 6 per-cpu devices on unsupported Intel families, probing Nehalem MSRs (all gracefully rejected by rdmsr_safe), installing a phantom empty cpu_node0 sensordev (hw.sensors.dev_idmax 6->7) and a useless 1 Hz task per cpu. No panic, no corruption (M_ZERO softc pins sc_version=0; static arrays bound sensor counts for any version value) - functional/robustness defect only. Fix (family gate in probe+attach) validated on the guest: with it, kldload attaches nothing and dev_idmax stays 6.