{
  "finding_id": "DF-3955",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Source-certain error-path defect, amdgpu twin DF-3891 (Low). kv_parse_power_table (kv_dpm.c:2673-2677) on mid-loop kzalloc failure: kfree(rdev->pm.dpm.ps) without NULLing, num_ps (assigned only at :2700) stays 0, ps_priv objects of states 0..i-1 leak. radeon_pm.c:1448 discards kv_dpm_init()s -ENOMEM, so the device persists with the dangling pointer; kv_dpm_fini (:2861-2871) at detach then kfrees rdev->pm.dpm.ps a second time (silent kernel heap corruption) and its num_ps==0 loop skips the leaked ps_privs. Harness replays the exact sequence with the OOM injected: dangling pointer + leaked ps_priv count = 2 + silent second free on DFly libc. Runtime-inconclusive: no AMD GPU, and the trigger itself needs a small kzalloc to fail at boot under memory pressure on KV hardware (rare) - hence Low.",
  "exploit_chain": "boot-time memory pressure on KV APU -> kzalloc(sizeof(struct kv_ps)) fails mid-parse -> dangling rdev->pm.dpm.ps -> driver detach/unload -> kv_dpm_fini double free -> silent kernel heap corruption. Principled exploitability of a heap double-free exists but the gating makes it negligible; primarily DoS/robustness.",
  "evidence": "run.log: state 2: kzalloc(kv_ps) failed -> kfree(dpm.ps); return -ENOMEM, dangling dpm_ps = 0x8004a16c0 ; leaked ps_priv count = 2 ; num_ps = 0, SECOND FREE COMPLETED SILENTLY (userland no-abort; kernel: silent heap corruption); VERDICT.md; fix.diff",
  "kernel_refs": [
    "sys/dev/drm/radeon/kv_dpm.c:2675",
    "sys/dev/drm/radeon/kv_dpm.c:2700",
    "sys/dev/drm/radeon/kv_dpm.c:2861",
    "sys/dev/drm/radeon/kv_dpm.c:2868",
    "sys/dev/drm/radeon/radeon_pm.c:1448"
  ],
  "poc_changes": "No seed (pass-2 self-authored). One fix cycle: naive replay expected malloc(72) to fail on demand (it never does) - replaced with an explicit injected failure at state #2; also discovered DFly libc does NOT abort on double free, so the harness now reports the silent completion explicitly instead of implying a libc abort.",
  "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": 100,
  "guest_dirty": 0,
  "build_cmd": "cd /tmp/df395x && cc -O2 -Wall -o trigger_df3955 trigger_df3955.c",
  "run_cmd": "cd /tmp/df395x && ./trigger_df3955 && ./trigger_df3955 crash",
  "code_hash": "9b4c540bc9972b4672017f8b46dd892d42383e4ca04e8424ccc87a7b9fe5679c",
  "notes": "Distinct from pass-1 DF-1305/1306/1307. The radeon_pm.c:1448 error-swallow (shared enabler with DF-3953) turns a would-be-contained boot failure into a live dangling pointer.",
  "recommended_fix": "On the parse error path free the already-parsed ps_priv states, NULL rdev->pm.dpm.ps, and track num_ps incrementally (fix.diff); honor kv_dpm_init()s return value at radeon_pm.c:1448.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff authored against the read-only sys/ tree; not built - no AMD hardware on the guest. Removes both the double free and the leak by construction.",
  "fix_evidence": "findings/poc/DF-3955/fix.diff"
}