⬢ DragonFlyBSD Kernel Audit
DF-4951 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4951",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "vega12_pp_tables_uninitialize (vega12_processpptables.c:296-301) dereferences hwmgr->pptable with no NULL guard at its first statement. hwmgr_hw_inits err1/err2 error paths (hwmgr.c:257-262) already invoke pptable_fini once, leaving hwmgr->pptable NULL, while hwmgr->pm_en stays TRUE (hwmgr.c:216-219 only clears it for missing funcs) and pm.dpm_enabled is never cleared on error; a subsequent hwmgr_hw_fini -- second pp_table sysfs write (amdgpu_pm.c:463 -> amd_powerplay.c:676/:697 amd_powerplay_reset, gated only on pm_en), driver teardown or GPU reset (pp IP block status.hw not cleared by the reset path) -- re-enters the function and faults at phm_ppt_v3_information+16 (hwmgr.h:579-594). Reproduced on the audit guest with a faithful lifted-copy harness: CASE 2 (pp_table write whose re-init fails at backend_init -> fini-inside-init, then a second write) SIGSEGVs at fault address 0x10, the exact kernel-equivalent NULL deref; CASE 1 (healthy) and CASE 3 (header-check failure on the err: path, which leaks but never finis) survive, isolating the crash to the err1/err2 mode and evidencing the secondary kmem-leak (vega12:272 kzalloc never freed on init failure); PATCHED build with the fix.diff NULL guard survives. In-kernel path hardware-gated (no Vega12 ASIC on the QEMU guest).",
  "exploit_chain": "root pp_table sysfs write #1 (or runtime powerplay re-init) fails at backend_init/err2 -> pptable_fini already ran, hwmgr->pptable=NULL, pm_en/dpm_enabled stale true -> root pp_table write #2 / rmmod / GPU reset -> hwmgr_hw_fini -> vega12_pp_tables_uninitialize -> kfree(NULL->power_saving_clock_max) load at NULL+16 -> kernel panic. DoS only: fixed NULL offset, no data control; requires one failed re-init plus a root-triggered (or hardware-failure) second fini.",
  "evidence": "run.log (CASE 2: >>> SIGSEGV: fault address 0x10 (power_saving_clock_max = pptable + 0x10) + PANIC-CLASS FAULT REPRODUCED; CASE 1 clean; CASE 3 survives showing err:-path leak); run.stability.log (repeat runs); fix_run.log (PATCHED: case 2 + case 4 survive, PATCHED_RUN_RC=0); fix_build.log (full amdgpu.ko rebuild with fix.diff, -Werror, RC=0, vega12_processpptables.o at :346); fix.diff (git apply --check OK)",
  "kernel_refs": [
    "sys/dev/drm/amd/powerplay/hwmgr/vega12_processpptables.c:296",
    "sys/dev/drm/amd/powerplay/hwmgr/vega12_processpptables.c:301",
    "sys/dev/drm/amd/powerplay/hwmgr/vega12_processpptables.c:272",
    "sys/dev/drm/amd/powerplay/hwmgr/vega12_processpptables.c:316",
    "sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:222",
    "sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:229",
    "sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:257",
    "sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:267",
    "sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:280",
    "sys/dev/drm/amd/powerplay/amd_powerplay.c:660",
    "sys/dev/drm/amd/powerplay/amd_powerplay.c:676",
    "sys/dev/drm/amd/powerplay/amd_powerplay.c:697",
    "sys/dev/drm/amd/amdgpu/amdgpu_pm.c:463",
    "sys/dev/drm/amd/amdgpu/amdgpu_pm.c:1992",
    "sys/dev/drm/amd/powerplay/inc/hwmgr.h:579"
  ],
  "poc_changes": "authored fresh this run (pass 2); no seed PoC existed",
  "attempts": 3,
  "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": 420,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh  (cc -O2 -Wall -o vega12_dfini_null vega12_dfini_null.c on the guest)",
  "run_cmd": "sh run.sh  (./vega12_dfini_null)",
  "code_hash": "ecfd2bf38041da40f04bb71e01ad15d84fad8db5469839fa020bcd8e26292c54",
  "notes": "lifted-copy harness per DF-1179/DF-4395/DF-4545 convention (in-kernel path needs a Vega12 ASIC; guest has only QEMU std VGA -- env.txt). Secondary defect observed but not separately filed: vega12_pp_tables_initialize leaks the hwmgr->pptable kzalloc (vega12:272) on every check/init failure because hwmgr_hw_inits err: path (hwmgr.c:223-224) never finis; CASE 3 of the harness demonstrates it (recovered only by the next fini). Also audited and killed this pass: the ignored phm_copy_*_limits_array returns at vega12:217-224/:252-253 (DF-4545 class) -- no vega12 consumer ever reads od_settings_*/power_saving_clock_* (only written+freed), so NULL arrays cannot be dereferenced; the #if 0 vega12_get_powerplay_table_entry off-by-one (entry_index <= ucNumEntries, :384) is dead code.",
  "recommended_fix": "NULL-guard early return in vega12_pp_tables_uninitialize (fix.diff); separately, hwmgr_hw_inits err: path should fini the partially initialized pptable to close the leak",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Patched kernel not runnable on the guest (no Vega12 ASIC). fix.diff is git-apply-able (host + guest), compiles clean in a full amdgpu.ko module build under the real kernel toolchain with -Werror (fix_build.log, RC=0, 0 diagnostics), and the harness PATCHED control survives the previously-fatal sequence.",
  "fix_evidence": "fix.diff; fix_build.log (full module rebuild RC=0, vega12_processpptables.o recompiled at log:346-347, 0 error: lines); fix_run.log (PATCHED cases 2/4 survive, PATCHED_RUN_RC=0); guest /usr/src restored + md5-verified (085571ce1e8f9c2fafdd71e4e3b2cc95)"
}