# DF-3955 VERDICT

**Verdict: INCONCLUSIVE at kernel level — source-certain error-path defect
(free + later free-again + leak); the exact sequence replayed in userland
completes silently on DragonFly libc, which — like the kernel's kmalloc/kmem
heap — performs no double-free detection. Confidence: likely (the mid-loop
kzalloc failure itself is memory-pressure-gated and cannot be forced without
hardware).**

## Trace

1. kv_parse_power_table allocates `rdev->pm.dpm.ps` (ucNumEntries radeon_ps
   structs, kv_dpm.c:2660-2663) then per-state `ps_priv` kv_ps structs
   (:2673). If the i-th `kzalloc` fails: `kfree(rdev->pm.dpm.ps)` (:2675),
   return -ENOMEM. The pointer is left dangling; `rdev->pm.dpm.num_ps` is
   only assigned AFTER the loop (:2700) so it stays 0 — hiding the i already
   parsed `ps_priv` objects from kv_dpm_fini's loop (leak).

2. kv_dpm_init returns the error (kv_dpm.c:2787-2789) — and
   radeon_pm_init_dpm (radeon_pm.c:1448) throws it away, so the driver
   proceeds with DPM (enable fails later on real hardware paths, but the
   dangling pointer persists regardless of that outcome).

3. On module unload / device detach: radeon_pm_fini → radeon_pm_fini_dpm
   (radeon_pm.c:1705) → radeon_dpm_fini → kv_dpm_fini (kv_dpm.c:2861-2871):
   num_ps==0 skips the ps_priv loop (leak confirmed), then
   `kfree(rdev->pm.dpm.ps)` frees the already-freed block a second time.

4. Also note: even before fini, any dereference of `rdev->pm.dpm.ps` between
   the failed parse and teardown hits freed memory (UAF read); in the enable
   path the DF-3953 NULL boot_ps deref usually fires first (panic), which is
   why this is Low rather than Medium.

## Harness result

- Analysis mode: prints the dangling pointer, `leaked ps_priv count = 2`,
  `num_ps = 0` and stops before the second free (exit 0).
- Crash mode: performs free → free-again with the failure injected; DragonFly
  userland malloc does not abort ("SECOND FREE COMPLETED SILENTLY") — the
  kernel heap likewise corrupts silently rather than panicking, which is the
  dangerous property being demonstrated.

## Why Low

Trigger requires a small kzalloc to fail during boot-time VBIOS parse on KV
hardware (memory pressure). Double-free impact in the kernel is heap
corruption (potentially exploitable in principle), but the gating makes
practical exploitation negligible; matches amdgpu DF-3891 (Low).

## Fix validation

fix.diff NULLs the pointer, frees the already-parsed ps_priv states, and
counts them into num_ps before returning. Not built on the guest (no AMD GPU):
`fix_status: not_testable`. By inspection the fix removes both the double
free and the leak.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
