# DF-4162 — VERDICT

**Status: inconclusive (source-level certain, runtime hardware-gated).**
**Expected impact if hardware present: drm-attach panic / suspend-resume panic /
double-free at unload on crafted-VBIOS or init-failed radeon DPM — the systemic
root enabler of DF-4022/3972/4117/4118/4124/4125/4143/4144.**

## Reproduced?

No — the audit guest has no AMD/ATI GPU (env.txt: virtio VGA only, zero 0x1002
PCI devices, `hw.drm` unknown oid). Per the DF-4022 family convention: source
certain, runtime inconclusive.

## Root-cause proof (path:line)

1. `radeon_pm_init_dpm()` invokes the asic init **as a statement**:
   `radeon_dpm_init(rdev);` (radeon_pm.c:1448). The macro expands to
   `rdev->asic->dpm.init((rdev))` (radeon.h:2793) — an `int` return — which is
   discarded. Upstream's `radeon_pm_init_dpm` contains
   `ret = radeon_dpm_init(rdev); if (ret) goto dpm_failed;` at the same point.
2. Failure semantics of the dispatch inits:
   * hard failure (`-EINVAL`/`-ENOMEM`) from parse errors — swallowed at :1448;
   * **silent success with `boot_ps == NULL`**: `boot_ps` is only assigned when
     a state carries `ATOM_PPLIB_CLASSIFICATION_BOOT` inside the per-state
     parse loops (rv770_dpm.c:2172-2173, rv6xx_dpm.c:1811-1812,
     trinity_dpm.c:1705, si_dpm.c:6727, kv_dpm.c:2599); no `*_dpm_init`
     validates it (grep: zero `boot_ps == NULL` checks in sys/dev/drm/radeon).
     `rv7xx_parse_power_table` returns 0 with `boot_ps` unset
     (rv770_dpm.c:2271-2329) — so honoring the return alone does NOT close this
     half; the hub-level `boot_ps` gate in fix.diff does.
3. With the error dropped, :1449 publishes
   `current_ps = requested_ps = boot_ps` (NULL/dangling), :1450-1451 can walk
   `ps[]` via `radeon_dpm_print_power_states`, :1452 runs `radeon_dpm_setup_asic`,
   :1453 runs `radeon_dpm_enable` → per-asic enables deref `boot_ps`
   (rv770_dpm.c:1901, rv6xx_dpm.c:1577, btc/trinity/cypress twins) → page fault
   at drm attach (= DF-4022/4118/4124/4143/3972 boot panics).
4. Even when `radeon_dpm_enable` fails into `dpm_failed`, the dangling `ps`
   survives; `radeon_pm_fini_dpm` → `radeon_dpm_fini` → `kfree(ps)` again
   (= DF-4117/4125/4144 double frees), and `radeon_pm_suspend_dpm` (:1262)/
   `radeon_pm_resume_dpm` (:1320)/fini's `radeon_dpm_disable` (:1694) re-deref
   `boot_ps` because `pm_method` stays `PM_METHOD_DPM` — the second swallow
   layer: every asic `*_init` calls `radeon_pm_init(rdev);` as a statement
   (si.c:6874, ni.c:2432, cik.c:8653, evergreen.c:5235, rv770.c:1962,
   r600.c:3321, …).

## Does the central fix make the six family NULL-boot_ps panics unreachable?

**Yes for the enable/boot side, and for suspend/resume/fini-disable, via one
file.** With fix.diff:
* init error → `dpm_init_failed` → no `setup_asic`, no `enable`, `dpm_enabled`
  stays false → `radeon_pm_compute_clocks_dpm` returns at :1817 → no
  `change_power_state_locked`, no `set_power_state` → the family's
  `get_sclk/get_mclk/enable` NULL derefs cannot run;
* no-BOOT-state-but-init-returned-0 → caught by the explicit `boot_ps` gate;
* suspend/resume/fini-disable are gated on `boot_ps` (needed because the asic
  `*_init` swallow layer keeps `pm_method == DPM` after failed init);
* dangling `ps` is scrubbed to NULL so the unload-time `*_dpm_fini` kfree is a
  no-op instead of a double free.
Residual: per-asic extended-table double frees (DF-4023-style ext tables freed
by parse error paths but left non-NULL) are not fully covered by the hub scrub;
those need the already-filed dispatch fixes. The asic `*_init` void-call of
`radeon_pm_init` (second layer) is left as-is to keep the fix single-file and
minimal; with the hub gating, that layer only causes a lost error message.

## Trigger (on hardware)

Identical to DF-4022's: crafted VBIOS PowerPlayInfo without a BOOT-classified
state (or `ucStateEntrySize<=1`), or any dpm.init failure (missing/failing SMC
upload, parse OOM) on rv6xx/rv7xx/evergreen/btc/trinity/si/cik. Expected:
unpatched — attach panic (family signature); patched — "radeon: dpm
initialization failed", driver up in degraded no-DPM mode, clean unload.

## Fix validation

`git apply --check` clean against the read-only tree. No runtime validation
possible (guest lacks radeon hardware). Composes with DF-4163's
`cancel_work_sync` hunk (different region of `radeon_pm_fini_dpm`).

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