DF-4493 / verdict.json
{ "finding_id": "DF-4493", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Reproduced at logic level with the verbatim replica (harness modes 4493/4493b): a PowerPlayInfo table with no BOOT-classified state leaves rdev->pm.dpm.boot_ps NULL (rs780_dpm.c:741-742 is the only assignment), radeon_pm_init_dpm discards the init return (radeon_pm.c:1448) and still calls radeon_dpm_enable (:1453) -> rs780_get_ps(NULL) reads NULL->ps_priv at 0x28 -> SIGSEGV (kernel: page-fault panic); ucStateEntrySize==1 makes the `if (ucStateEntrySize - 1)` guard (:822) skip every state while num_ps is still set (:842), leaving all ps_priv NULL -> rs780_dpm_print_power_state :946 derefs ps->sclk_low at 0x8 -> SIGSEGV. Fault addresses match the kernel struct layouts exactly (offsetof radeon_ps.ps_priv = 40, igp_ps.sclk_low = 8). RS780 twin of DF-4187 (sumo) / DF-4124 (rv6xx) / DF-4143 (trinity) / DF-4118 (cypress). Kernel-level repro hardware-gated (no RS780 IGP in the QEMU guest). Fix proven: enable refuses NULL boot_ps; parse rejects ucStateEntrySize < 2; radeon.ko builds under -Werror (MAKE_RC=0).", "exploit_chain": "crafted VBIOS PowerPlayInfo (no BOOT class, or ucStateEntrySize==1) -> parse returns success with boot_ps/ps_priv NULL -> radeon_pm.c:1448 swallows nothing to swallow (parse succeeded) -> dpm enable runs -> NULL->ps_priv read at 0x28 -> kernel page-fault panic (local DoS on probe / first mode set / radeon_dpm=1 boot print)", "evidence": "run.log ===== mode 4493 =====: boot_ps=0x0 then SIGNAL 11 at address 0x28, exit=99; ===== mode 4493b =====: ps[0].ps_priv=0x0 then SIGNAL 11 at address 0x8, exit=99; fixed sections: DRM_ERROR: no boot power state, refusing to enable DPM / DRM_ERROR: invalid state entry size 1, exit=0; radeon_module_build.log MAKE_RC=0 under -Werror", "kernel_refs": [ "sys/dev/drm/radeon/rs780_dpm.c:600", "sys/dev/drm/radeon/rs780_dpm.c:608", "sys/dev/drm/radeon/rs780_dpm.c:78", "sys/dev/drm/radeon/rs780_dpm.c:822", "sys/dev/drm/radeon/rs780_dpm.c:842", "sys/dev/drm/radeon/rs780_dpm.c:946", "sys/dev/drm/radeon/radeon_pm.c:1448" ], "poc_changes": "wrote harness from scratch (no seed); -fno-delete-null-pointer-checks + volatile clock sink required so the NULL loads trap with kernel semantics instead of being folded by GCC", "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": 200, "guest_dirty": 0, "build_cmd": "./build.sh (on audit guest, cc 8.3, -fno-delete-null-pointer-checks)", "run_cmd": "./run.sh (modes 4493 4493b; full matrix in run.log)", "code_hash": "3b7698d1a8d20944dd3c2ea4c0010146536ed001ff5cf1034c4c4ac650591741", "notes": "known finding DF-1650 excluded (pass-1). Trigger B (ucStateEntrySize==1) additionally leaves every ps_priv NULL for set_power_state/get_sclk/force_performance_level consumers; trigger A covers the DF-4187 shape. Both die on the same unchecked rs780_get_ps() contract.", "recommended_fix": "refuse to enable DPM without a boot power state (boot_ps NULL check in rs780_dpm_enable) and reject ucStateEntrySize < 2 in rs780_parse_power_table, as in fix.diff", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "harness_fixed 4493 returns -EINVAL before any deref (no boot power state); 4493b rejected at parse (invalid state entry size 1); combined fix builds radeon.ko under -Werror (MAKE_RC=0)", "fix_evidence": "run.log fixed sections for modes 4493/4493b (exit=0, canary_violations=0); radeon_fix_apply.log hunk 1 (enable guard) and hunk 4 (entry-size check); radeon_module_build.log MAKE_RC=0" } |