# DF-4371 VERDICT — dangling dyn_state entries → double free (r600_dpm.c error paths)

## Bottom line

**Certain by static proof; not reproduced at runtime — the audit VM has no
radeon GPU, and the trigger additionally requires an induced allocation
failure during VBIOS parsing.** Same defect family as DF-3973 (caller-side
btc instance), DF-4023/DF-4117/DF-4125 (`ps` pointer); this is the **root
site inside r600_dpm.c** shared by all six family callers.

## Why the double free is real (path:line)

1. `r600_dpm.c:927-931` — `vddc_dependency_on_sclk` parsed OK
   (`entries` = live kzalloc'd pointer).
2. `r600_dpm.c:936-941` — the `vddci_dependency_on_mclk` parse fails (its
   internal `kzalloc` at `r600_dpm.c:829` returned NULL → `-ENOMEM`):
   ```c
   if (ret) {
           kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
           return ret;
   }
   ```
   `vddc_dependency_on_sclk.entries` is now dangling; its `count` may also be
   stale from a previous partially-parsed attempt.
   Two-pointer variant at `r600_dpm.c:949-953` (vddc-on-mclk failure), three-
   pointer variant at `r600_dpm.c:961-966` (mvdd failure).
3. Caller propagates: e.g. `btc_dpm.c:2577-2579` `ret =
   r600_parse_extended_power_table(rdev); if (ret) return ret;`
   (identical: `ni_dpm.c:4075`, `si_dpm.c:6953`, `kv_dpm.c:2731`,
   `trinity_dpm.c:2001`, `ci_dpm.c:5776-5779`).
4. `radeon_pm_init` dpm path fails → `rdev->pm.dpm_enabled = false`
   (`radeon_pm.c:1465,1470`). Device init failure is *not* fatal for the
   driver session; teardown always follows at unload/reboot.
5. `radeon_pm.c:1705` — `radeon_dpm_fini(rdev);` runs **unconditionally**
   (no `dpm_enabled` check; line 1705 sits outside the `if (rdev-
   >pm.dpm_enabled)` block that ends at 1704).
6. → `btc_dpm_fini()` (`btc_dpm.c:2727`) / `ni_dpm_fini` (`ni_dpm.c:4276`) /
   `si_dpm_fini` (`si_dpm.c:7088`) / `kv_dpm_fini` (`kv_dpm.c:2870`) /
   `trinity_dpm_fini` (`trinity_dpm.c:2091`) / `ci_dpm.c:5713` →
   `r600_free_extended_power_table()` (`r600_dpm.c:1299-1315`) →
   `kfree(dyn_state->vddc_dependency_on_sclk.entries);` — **second free of
   the same pointer**.

DragonFly `kfree()` of an already-freed slab object is a double free /
free-list corruption (uma zone poisoning may catch it as a panic; on a
groomed heap it is a classic UAF-style corruption primitive). Precondition:
attacker controls the VBIOS (hostile card / modified ROM / VFCT override via
`radeon_get_bios` ACPI path `radeon_bios.c:717`) **and** can force one
kzalloc failure at attach (failslab injection or real memory pressure).

## Verification attempts on the audit VM

* Guest: DragonFly 6.5-DEVELOPMENT x86_64, no GPU (`pciconf`: only QEMU
  virtio VGA 0x1111:1234), no radeon module loadable, no `/dev/dri`.
* The radeon DPM attach path cannot run at all → the parse/failure/fini
  chain is unreachable at runtime on this VM.
* Static verification only, therefore status **not_reproduced**, impact
  `none` (on this guest). Confidence in the code defect itself: certain —
  every hop above is a direct citation.

## Severity calibration

Identical trigger model and impact class as DF-3973 / DF-4023 / DF-4117 /
DF-4125 (all Medium, `CVSS:3.1/AV:P/AC:H/PR:L`, CWE-416, memcorrupt bucket).
Kept consistent: Medium, `CVSS:3.1/AV:P/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H`.

## Fix

`fix.diff`: (a) NULL each pointer immediately after the error-path kfree
(sites :939, :950-951, :962-964); (b) make `r600_free_extended_power_table()`
idempotent by NULLing every pointer it frees — this also protects against the
caller-side free-then-fini pattern (DF-3973's second path) reaching the same
double free. Verified `patch -p1 --dry-run` → APPLIES_CLEAN on a scratch
copy. Runtime fix validation impossible on this VM (no radeon hardware):
`fix_status: not_testable`.

## kernel_refs

* sys/dev/drm/radeon/r600_dpm.c:939,950,951,962,963,964 (dangling kfrees)
* sys/dev/drm/radeon/r600_dpm.c:829-831 (the only failure source)
* sys/dev/drm/radeon/r600_dpm.c:1299-1315 (second free)
* sys/dev/drm/radeon/radeon_pm.c:1705 (unconditional dpm_fini)
* sys/dev/drm/radeon/btc_dpm.c:2577-2579,2727 (caller chain instance)
* sys/dev/drm/radeon/ni_dpm.c:4075,4276; si_dpm.c:6953,7088;
  kv_dpm.c:2731,2870; trinity_dpm.c:2001,2091; ci_dpm.c:5776,5713

## 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.
