DF-4903 / verdict.json
{ "finding_id": "DF-4903", "status": "untested", "reproduced": 0, "impact": "leak", "confidence": "likely", "verdict": "Kernel path is certain from source but cannot execute on the Intel/QEMU audit guest (kldload powernow fails at the CPUID 0x80000007 gate, console: MOD_LOAD error 2), so no kernel-level reproduction was possible. A userland harness replicating the exact struct layout and expressions (run as uid=1001 on the guest, run.log) demonstrates the full flow: k8_get_curfreq()s -1 sentinel becomes UINT_MAX in the unsigned freq parameter, the match loop exits with i==n_states, and the tail at powernow.c:311 reads state_table[n_states] \u2014 an uninitialised kmalloc(M_DEVBUF) word for n_states<16 \u2014 which lands in the global cpuspeed exposed world-readable via sysctl machdep.powernow.frequency.current. Distinct root cause from DF-1960 (there the whole table is uninitialised because no PST matched; here decode succeeded but the sentinel indexes past the initialised prefix).", "exploit_chain": "Passive 4-byte kernel-heap disclosure readable by any local user (sysctl read needs no privilege, kern_sysctl.c:1446 gates writes only). Requires AMD K8 with the boot-time fid/vid not present in the BIOS PST \u2014 value is residual slab data, limited info value, no escalation primitive by itself.", "evidence": "run.log (harness output: cpuspeed = 0xa5a5a5a5 as uid=1001), env.txt (guest uname + kldstat showing powernow.ko loaded-but-inert after MOD_LOAD error 2), sim_tailread.c (flow replica), VERDICT.md", "kernel_refs": [ "sys/dev/powermng/powernow/powernow.c:223", "sys/dev/powermng/powernow/powernow.c:246", "sys/dev/powermng/powernow/powernow.c:310", "sys/dev/powermng/powernow/powernow.c:311", "sys/dev/powermng/powernow/powernow.c:366", "sys/dev/powermng/powernow/powernow.c:392", "sys/dev/powermng/powernow/powernow.c:417" ], "poc_changes": "No seed PoC existed; harness authored fresh from the kernel source with identical struct layout, sentinel and comparison expressions; MSR transition phases stubbed.", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 45, "guest_dirty": 0, "build_cmd": "cc -Wall -O2 -o sim_tailread sim_tailread.c", "run_cmd": "./sim_tailread", "code_hash": "9b0352a60b18c822cc57c55dde993cf7654eba1380792b45ed973f33b90956e2", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Fix validation not run: the vulnerable kernel path requires AMD K8 hardware (CPUID 0x80000007 EDX bit 6) absent from the audit guest; fix.diff is line-accurate (bail out when i==n_states; guard the powernow_init call site) and verified to apply cleanly with patch(1).", "fix_evidence": "fix.diff applies clean: checking file powernow.c / DF4903_APPLIES_CLEAN", "recommended_fix": "In k8_powernow_setperf return EINVAL when the match loop exits with i==n_states, and in powernow_init only call setperf when k8_get_curfreq() > 0.", "notes": "Pass-2 finding; do not confuse with DF-1960 (different root cause, same leak class). Module remains kldstat-resident after MOD_LOAD error 2 on this guest but is inert (no sysctls, k8pnow_current_state NULL)." } |