{
  "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."
}