# DF-4022 — NULL-deref panic via `boot_ps == NULL` in rv770_dpm_enable / rv770_init_smc_table

**File:** `sys/dev/drm/radeon/rv770_dpm.c` (pass 2)
**Class:** CWE-476 NULL pointer dereference → kernel panic (DoS)
**Hardware gate:** RV770/RV730/RV710/RV740 GPU with (crafted) VBIOS AtomBios
PowerPlayInfo table. Same threat model as DF-1333/1334/1335 (crafted VBIOS via
PCIe passthrough / hotplug / reflash).
**Status:** source-level certain; runtime hardware-gated (guest has virtio VGA
only — see `env.txt`). Per family convention (DF-3610/3646/3754/3953/3972) this
is `inconclusive` at runtime, `certain` at source level.

## Root cause

`rv7xx_parse_power_table()` (rv770_dpm.c:2271-2329) only ever sets
`rdev->pm.dpm.boot_ps` — inside `rv7xx_parse_pplib_non_clock_info()`
(rv770_dpm.c:2172-2173) — and that function is only reached when
`power_info->pplib.ucStateEntrySize - 1` is non-zero (rv770_dpm.c:2304), i.e.
`ucStateEntrySize >= 2`. Two fully VBIOS-controlled conditions therefore leave
`boot_ps == NULL` while `num_ps = ucNumStates` is still published
(rv770_dpm.c:2327):

1. `ucStateEntrySize <= 1` (states are counted but never parsed), or
2. no parsed state carries `ATOM_PPLIB_CLASSIFICATION_BOOT`.

Additionally `rv770_dpm_init()` failure of any kind
(`r600_get_platform_caps()` fail at rv770_dpm.c:2364-2366;
`rv7xx_parse_power_table()` fail at :2368-2370) leaves `boot_ps` NULL, and
its return value is **ignored** by the caller (`radeon_pm.c:1448`), so the
enable path runs regardless.

## Crash chain

```
radeon_pm_init_dpm()                       radeon_pm.c:1448  radeon_dpm_init() return IGNORED
  radeon_pm.c:1449                         current_ps = requested_ps = boot_ps  (NULL)
  radeon_pm.c:1453  radeon_dpm_enable()
    rv770_dpm_enable()                     rv770_dpm.c:1898
      boot_ps = rdev->pm.dpm.boot_ps       rv770_dpm.c:1901  (NULL, never checked)
      rv770_init_smc_table(rdev, NULL)     rv770_dpm.c:1956
        boot_state = rv770_get_ps(NULL)    rv770_dpm.c:1170 -> :52-57  rps->ps_priv
        pi->boot_sclk = boot_state->low.sclk  rv770_dpm.c:1176
```

`rv770_get_ps(NULL)` reads `NULL->ps_priv` → page-0 fault in kernel mode →
panic ("Fatal trap 12: page fault while in kernel mode"). The same NULL
`boot_ps`/`requested_ps` is later dereferenced on every
`rv770_dpm_get_sclk`/`get_mclk` (rv770_dpm.c:2554-2572) and on the resume
path (radeon_pm.c:1320-1322).

When `ucStateEntrySize == 1`, `ps_priv[i]` also stays NULL for every state
(rv770_dpm.c:2304-2325 skips the kzalloc), so even a "BOOT" state that
magically existed would still deref NULL via `ps_priv`.

## Impact

Kernel panic at device attach (boot or PCIe hotplug) on RV770-family GPUs
with a malformed/malicious VBIOS power table; reboot-loop DoS on such a
system. No info leak / no write primitive (pure NULL deref).

rv770-family twin of DF-3972 (btc), DF-3953 (kv), DF-3754 (ni),
DF-3646 (ci), DF-3610 (si). The rv770 instance was NOT previously filed
(pass 1 filed only DF-1333/1334/1335 against this file).

## Fix

`rv770_dpm_enable()` must refuse to run without a boot state, and
`radeon_pm_init_dpm()` must not ignore `dpm.init` failure. See `fix.diff`.

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