DF-3754 / verdict.json
{ "finding_id": "DF-3754", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Source-certain NULL-deref, ni twin of DF-3610 (si) / DF-3646 (ci). rdev->pm.dpm.boot_ps is set only in ni_parse_pplib_non_clock_info (ni_dpm.c:3914-3915) behind the ucStateEntrySize!=1 guard (ni_dpm.c:4018); crafted VBIOS shapes (ucNumStates==0, ucStateEntrySize==1, or no ATOM_PPLIB_CLASSIFICATION_BOOT state) leave it NULL while ni_parse_power_table returns 0. radeon_pm_init_dpm ignores the dpm.init rc (radeon_pm.c:1448), publishes current_ps=requested_ps=boot_ps (NULL, :1449) and calls radeon_dpm_enable (:1453) -> ni_dpm_enable:3589/3641 -> ni_init_smc_table:1943/1975 -> ni_populate_smc_initial_state:1683 -> ni_get_ps(NULL)->ps_priv = read at NULL+0x28 -> unrecoverable page fault / panic at default-enabled DPM (BARTS/TURKS/CAICOS/CAYMAN/ARUBA). The ucStateEntrySize==1 shape also leaves ps_priv NULL for all states -> first power-state change faults in ni_update_requested_ps (ni_dpm.c:3576/3581, *NULL read). Verified via a userspace logic harness executing the verbatim call graph over a synthetic VBIOS: children SIGSEGV at exactly 0x28 and 0x0 (run.log); no AMD GPU exists on the virtio-only audit guest (env.txt), so the kernel-context panic itself is hardware-gated. No escalation: the pointer is deterministic NULL. fix.diff (ni_dpm_enable boot_ps guard, mirrors si fix) applies clean, compiles -Werror clean as ni_dpm.o in the real kernel tree, and the harness fixed-path refuses with -EINVAL.", "exploit_chain": "None possible: deterministic NULL dereference, no attacker-controlled offset or content; boot-time DoS (panic) with a crafted VBIOS only.", "evidence": "run.log [A]/[A2] (child SIGSEGV at 0x28 and 0x0 = the exact kernel fault addresses), harness.c (verbatim ni_parse_power_table walk incl. the ucStateEntrySize-1 promotion quirk + consumer call graph), fix_run.log ([B] fixed path refuses), fix_build.log (patched ni_dpm.o -Werror clean), env.txt (virtio-only guest, radeon.ko+fw present, no 0x1002 PCI dev)", "kernel_refs": [ "sys/dev/drm/radeon/ni_dpm.c:3914", "sys/dev/drm/radeon/ni_dpm.c:4018", "sys/dev/drm/radeon/ni_dpm.c:3589", "sys/dev/drm/radeon/ni_dpm.c:3641", "sys/dev/drm/radeon/ni_dpm.c:1943", "sys/dev/drm/radeon/ni_dpm.c:1975", "sys/dev/drm/radeon/ni_dpm.c:1683", "sys/dev/drm/radeon/ni_dpm.c:733", "sys/dev/drm/radeon/ni_dpm.c:3576", "sys/dev/drm/radeon/radeon_pm.c:1448", "sys/dev/drm/radeon/radeon.h:1355" ], "poc_changes": "No seed existed; harness written from scratch (verbatim-replica methodology of DF-3610). Two iterations: missing errno.h include; unused-var cleanup via faithful clock_info use.", "attempts": 2, "guest_uname": "DragonFly dfbsd 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": 55, "guest_dirty": 1, "build_cmd": "cc -O2 -Wall -o harness harness.c", "run_cmd": "./harness", "code_hash": "f6dcc934748d7101d1e495acfa8df1e2e40610367098f655a339612da4537e27", "notes": "Pass-2 finding for sys/dev/drm/radeon/ni_dpm.c (Dillon bucket base:dev). DPM is default-enabled for NI asics when rlc/smc firmware is present (radeon_pm.c:1546-1572, radeon_dpm=-1 auto). Distinct from known DF-1203 (ucStateEntrySize parse WRITE overflow) and DF-1204 (ss.rate div0): this is the unvalidated boot_ps/ps_priv NULL on the consume side.", "recommended_fix": "Guard ni_dpm_enable: refuse DPM enable when rdev->pm.dpm.boot_ps == NULL (return -EINVAL); see fix.diff.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fixed (compile + harness level): fix.diff applies clean alone and stacked with DF-3755s fix, compiles -Werror clean as a kernel object (make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC ni_dpm.o), and the harness fixed-path returns -EINVAL with no dereference. Live-HW boot test impossible on the virtio-only guest.", "fix_evidence": "fix_build.log (patched ni_dpm.c -Werror compile, guard present at :3593); fix_run.log ([B] rc=-EINVAL, no fault); guest /usr/src restored to pristine and verified by md5 after validation." } |