{
  "finding_id": "DF-3611",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "radeon twin of amdgpu DF-3588. si_parse_power_table kfrees rdev->pm.dpm.ps at :6855 when a ni_ps kzalloc fails, but leaves the pointer dangling, num_ps==0 (so the earlier ps_priv allocations leak) and returns -ENOMEM. radeon_pm_init_dpm:1448 ignores the init return; on driver unload si.c:6945 -> radeon_pm_fini:1705 calls radeon_dpm_fini UNCONDITIONALLY (no dpm_enabled check) -> si_dpm_fini:7085 kfrees the dangling pointer: double free of a block that the heap has meanwhile recycled -> live-object free / cross-object UAF. Harness replicates the sequence with fault injection: the freed dpm.ps block is recycled by a live victim object; finis second free releases it; the next allocation aliases it and writes through the second owner clobber the first owners data (observed marker corruption). OOM-gated (needs the ni_ps kzalloc to fail while later allocs succeed), same trigger class and Low severity as the amdgpu twin.",
  "exploit_chain": "kzalloc failure at state i -> kfree(dpm.ps), pointer dangling, privs leaked -> init rc ignored -> heap recycles block -> driver unload -> radeon_dpm_fini unconditional -> kfree(dpm.ps) again -> live object freed -> UAF/type confusion for any same-size-class object",
  "evidence": "run.log [A]: victim object now lives at 0x8004904a0 (SAME block - recycled) ... >>> DOUBLE FREE of a LIVE object <<< ... victim->marker was silently CLOBBERED -> use-after-free; [B]: si_dpm_fini: dpm.ps == NULL -> no-op (no double free)",
  "kernel_refs": [
    "sys/dev/drm/radeon/si_dpm.c:6855",
    "sys/dev/drm/radeon/si_dpm.c:7085",
    "sys/dev/drm/radeon/radeon_pm.c:1448",
    "sys/dev/drm/radeon/radeon_pm.c:1705",
    "sys/dev/drm/radeon/si.c:6945"
  ],
  "poc_changes": "n/a (pass-2 finding authored with its harness; no seeded PoC to fix)",
  "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": 90,
  "guest_dirty": 0,
  "build_cmd": "cd findings/poc/DF-3611 && sh build.sh",
  "run_cmd": "cd findings/poc/DF-3611 && sh run.sh",
  "code_hash": "a2ccba867562301dfabdfa8ed5d78ed1105571bb96430f80ffd1011138fe7ab6",
  "notes": "Harness-level reproduction (exact kernel expressions executed with crafted-VBIOS inputs; SIGSEGV/SIGFPE/corruption observed). No AMD SI GPU on the virtio-only QEMU guest -> no live radeon DPM path possible; radeon.ko present at /boot/kernel. Guest /usr/src restored to pristine (sha 774b9b851b3b4ccb...) after fix validation.",
  "recommended_fix": "see fix.diff",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "git apply --check OK (standalone and stacked with the other four si_dpm.c fixes); targeted module TU compile `make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC si_dpm.o` => rc=0, -Werror clean (87080 B). Harness fixed-path shows the primitive gone (fix.diff frees the already-parsed ps_priv states, NULLs rdev->pm.dpm.ps on the error path, and guards si_dpm_fini with `if (rdev->pm.dpm.ps)`. git apply --check OK; stacked module TU compile -Werror clean; harness [B] clean.)",
  "fix_evidence": "fix.diff frees the already-parsed ps_priv states, NULLs rdev->pm.dpm.ps on the error path, and guards si_dpm_fini with `if (rdev->pm.dpm.ps)`. git apply --check OK; stacked module TU compile -Werror clean; harness [B] clean."
}