DF-5230 / verdict.json
{ "finding_id": "DF-5230", "status": "reproduced", "verdict": "uvd_v4_2_resume() dereferences rdev->uvd_fw->datasize at sys/dev/drm/radeon/uvd_v4_2.c:51 with no guard. The cik_uvd_start() caller is guarded (has_uvd, cik.c:8167; vcpu_bo, radeon_uvd.c:286), but the KV DPM ungate caller is not: any suspend or pm-fini on a DPM-enabled KV/CIK APU (KAVERI/KABINI/MULLINS) whose UVD firmware kmods are absent (uvd_fw NULL after failed radeon_uvd_init, radeon_uvd.c:137/176; has_uvd cleared cik.c:8156 while DPM stays up from SMC fw) reaches kv_dpm.c:1628 via cik.c:8545 -> radeon_pm.c:1257 -> radeon.h:2797 -> kv_dpm.c:1305,1316,1608 (caps_uvd_pg always true kv_dpm.c:2773; uvd_power_gated set true at boot kv_dpm.c:1300) and panics. The guest has no AMD GPU, so verification used a harness kld that reconstructs the exact post-failed-init radeon_device state (uvd_fw=NULL, fw_header_present=false, gpu_addr=0, max_handles=10) and calls the PRODUCTION uvd_v4_2_resume compiled into a freshly built radeon.ko: deterministic panic fault virtual address = 0x10 (offsetof(struct firmware, datasize)) at uvd_v4_2_resume+0x30: movq 0x10(%rdx),%rdx, reproduced twice, the second from a fresh vm.sh reset with reverted source; fault precedes the first WREG32 so no MMIO is touched. With fix.diff (one-line uvd_fw==NULL -> -EINVAL guard) applied in the guest /usr/src and radeon.ko rebuilt, the identical trigger prints survived, uvd_v4_2_resume returned -22 and the guest stays up. Field trigger is hardware-gated (KV APU + SMC-without-UVD fw config); impact ceiling is a local DoS panic (pure data read, no write primitive).", "reproduced": true, "impact": "panic", "confidence": "certain", "exploit_chain": "", "evidence": "panic.txt + panic.2.txt (serial console: DF5230 markers, Fatal trap 12, fault VA 0x10, Stopped at uvd_v4_2_resume+0x30 movq 0x10(%rdx),%rdx -- twice, second from fresh reset); run.fixed.log / fix_run.log (patched radeon.ko: survived, uvd_v4_2_resume returned -22, guest up); VERDICT.md (full link-by-link production trigger chain with path:line); fix.diff (git apply --check clean); env.txt (no AMD PCI device on guest)", "kernel_refs": [ "sys/dev/drm/radeon/uvd_v4_2.c:51", "sys/dev/drm/radeon/kv_dpm.c:1628", "sys/dev/drm/radeon/kv_dpm.c:1608", "sys/dev/drm/radeon/kv_dpm.c:1305", "sys/dev/drm/radeon/kv_dpm.c:1300", "sys/dev/drm/radeon/kv_dpm.c:2773", "sys/dev/drm/radeon/radeon_pm.c:1257", "sys/dev/drm/radeon/radeon_pm.c:1694", "sys/dev/drm/radeon/radeon.h:2797", "sys/dev/drm/radeon/cik.c:8545", "sys/dev/drm/radeon/cik.c:8167", "sys/dev/drm/radeon/radeon_uvd.c:137", "sys/dev/drm/radeon/radeon_uvd.c:286", "sys/dev/drm/radeon/radeon_asic.c:2285", "sys/sys/firmware.h:51" ], "poc_changes": "no seed; harness written fresh (df5230.c: zeroed struct radeon_device + max_handles=10 == post-failed-radeon_uvd_init state, calls production radeon.ko symbol; MODULE_DEPEND removed because radeon.ko declares no MODULE_VERSION so a versioned dep always fails)", "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": 12, "guest_dirty": 0, "build_cmd": "cd /usr/src/sys/dev/drm/drm && make -j6 && cd ../radeon && make -j6 && cd /root/df5230 && make", "run_cmd": "kldload /usr/src/sys/dev/drm/drm/drm.ko && kldload /usr/src/sys/dev/drm/radeon/radeon.ko && kldload /root/df5230/df5230.ko", "code_hash": "ed116247c35bd29e2307005c8c35806438d8024c02f8478ca86c786f86cd0662", "notes": "synthetic-state harness calling the production function (no KV APU on guest); production chain proven statically path:line; fault is a data read -> DoS ceiling only; guest reset clean (vm.sh reset with-src) after validation; trigger context: DragonFly ships all radeon fw as separate opt-in radeonkmsfw_* kmods, so SMC-loaded-without-UVD is a natural config, not contrived", "recommended_fix": "one-line guard in uvd_v4_2_resume: if (rdev->uvd_fw == NULL) return -EINVAL; (mirrors has_uvd/vcpu_bo guards of the other paths)", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Baseline (stock radeon.ko): identical trigger panics (fault VA 0x10 at uvd_v4_2_resume+0x30), twice, second from a fresh vm.sh reset with reverted source. Patched (fix.diff in guest /usr/src, radeon.ko rebuilt): identical trigger returns -22, prints survived, guest stays up, kldload succeeds. The previously-observed panic is GONE under the fix.", "fix_evidence": "fix_run.log (patched-kernel run: survived/returned -22, guest up); fix_build.log (patch + incremental rebuild transcript); panic.txt/panic.2.txt (baseline); fix.diff" } |