# DF-4371 — r600_parse_extended_power_table error-path kfree leaves dangling
dyn_state entries pointers → double free in r600_free_extended_power_table

* File: `sys/dev/drm/radeon/r600_dpm.c` (:939, :950-951, :962-964 dangling
  kfree sites; :1299-1315 the second free), triggered from every DPM family
  caller (btc/ni/si/ci/kv/trinity) and completing at driver teardown.
* Severity: Medium — same family/calibration as DF-3973/DF-4023/DF-4117/DF-4125.
* Class: CWE-416/CWE-459 (double free / dangling pointer on error path).

## The bug

`r600_parse_clk_voltage_dep_table()` returns error only when its `kzalloc`
fails (`r600_dpm.c:829-831`). When the *second/third/fourth* table's parse
hits that failure, the error paths of `r600_parse_extended_power_table()`
free the *already-parsed* tables' entries but leave the pointers dangling:

```c
/* r600_dpm.c:936-941 (vddci-on-mclk failure frees vddc-on-sclk) */
if (ret) {
        kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
        return ret;                 /* pointer NOT set to NULL */
}
```
(same shape at :949-953 freeing two pointers, and :961-966 freeing three).

Every caller (e.g. `btc_dpm.c:2577-2579`, `ni_dpm.c:4075-4077`,
`si_dpm.c:6953-6955`, `kv_dpm.c:2731-2733`, `trinity_dpm.c:2001-2003`,
`ci_dpm.c:5776-5779`) propagates the error; dpm init fails. At unload or
reboot `radeon_pm_fini()` calls `radeon_dpm_fini()` **unconditionally**
(`radeon_pm.c:1705` — no `dpm_enabled` guard), dispatching to e.g.
`btc_dpm_fini()` (`btc_dpm.c:2727`) → `r600_free_extended_power_table()`
→ `kfree()` of the same, already-freed pointers → **heap double free**.

## Trigger (needs AMD hardware; documented, not runnable on audit VM)

1. radeon GPU (BTC/NI/SI/CI/KV/Trinity family) whose VBIOS carries a pplib4+
   PowerPlayInfo table with `usVddcDependencyOnSCLKOffset != 0` and
   `usVddciDependencyOnMCLKOffset != 0`.
2. Force the second parse's kzalloc to fail (kernel slab fault injection —
   `failslab` on the `drm` uma/slab, or genuine memory pressure at attach).
3. Device attach fails; `dpm_enabled = false`.
4. Unload/reboot → double free of `vddc_dependency_on_sclk.entries` (or the
   2/3-pointer variants).

## Artifacts
* `trigger.md` — the exact call chain and a fault-injection runbook
* `fix.diff` — NULL every pointer after kfree (both in the error paths and in
  `r600_free_extended_power_table`, making the teardown free idempotent);
  verified `patch -p1 --dry-run` APPLIES_CLEAN
* `VERDICT.md` — full analysis
