# DF-4951 — vega12_processpptables: double `pptable_fini` NULL deref

**File:** `sys/dev/drm/amd/powerplay/hwmgr/vega12_processpptables.c`
**Class:** CWE-476 (NULL pointer dereference) — kernel panic, root/hw-failure precondition
**Severity:** Low · **Bucket:** base:drm

## What

`vega12_pp_tables_uninitialize()` (vega12_processpptables.c:296-320) caches
`pp_table_info = hwmgr->pptable` and immediately dereferences it
(`kfree(pp_table_info->power_saving_clock_max)`, :301) with **no NULL
guard**. The caller contract makes `hwmgr->pptable == NULL` a reachable
state: `hwmgr_hw_init()`'s error paths `err1:`/`err2:` (hwmgr.c:257-262)
already invoke `pptable_fini()` once — freeing the pptable and NULLing
`hwmgr->pptable` — before returning an error, while `hwmgr->pm_en` stays
TRUE (it is only cleared when pptable funcs are missing, hwmgr.c:216-219)
and `pm.dpm_enabled` retains its stale boot-time TRUE (nothing clears it on
the error path).

Any subsequent `hwmgr_hw_fini()` then re-enters the function and faults at
NULL+offset. Reachable triggers after one failed powerplay re-init:

- a second root write to `/sys/class/drm/card0/device/pp_table`
  (amdgpu_pm.c:463 → amd_powerplay.c:676 `pp_dpm_set_pp_table`, gated only
  on `hwmgr && hwmgr->pm_en` → `amd_powerplay_reset` → `hwmgr_hw_fini`);
- driver teardown / GPU reset paths that reach `pptable_fini`
  (the pp IP block's `status.hw` was set at boot and is not cleared by
  `amd_powerplay_reset`).

The failing re-init itself is any `hwmgr_hw_init` failure at `err1`/`err2`
(backend_init / psm_init_power_state_table / phm_setup_asic /
enable_dsm failure — e.g. SMU task timeout after a pp_table swap, the
classic sleep/wake or table-upload hiccup).

## Reproduce (lifted-copy harness; in-kernel path needs a Vega12 ASIC)

```
./build.sh   # cc -O2 -Wall -o vega12_dfini_null vega12_dfini_null.c
./run.sh     # ./vega12_dfini_null
```

Expected (run.log):
- CASE 1 BOOT-OK (healthy boot + healthy reset): clean exit.
- CASE 2 BUG (write#1 → pptable_init OK, backend FAILS → err1 fini inside
  init; write#2 → fini again): **SIGSEGV fault address 0x10**
  (`power_saving_clock_max` at `phm_ppt_v3_information`+16 — kernel-x86-64
  offset) = the kernel panic-equivalent.
- CASE 3 CONTROL (write#1 fails at the header check → `err:` path leaks the
  fresh kzalloc but does NOT fini; write#2 frees it): survives — proving the
  crash specifically requires the err1/err2 (fini-inside-init) failure and
  demonstrating the secondary kmem-leak defect on the `err:` path.

Patched build: `cc -O2 -Wall -DPATCHED ...` → CASE 2/4 survive (fix_run.log).

## Fix validation

- `git apply --check fix.diff` OK (host tree and guest `/usr/src`).
- Full `amdgpu.ko` module rebuild with the fix under the real kernel
  toolchain, **-Werror**, `-j8`: RC=0 in 24 s, `vega12_processpptables.o`
  recompiled at fix_build.log:346-347, 0 diagnostics (fix_build.log).
- Guest `/usr/src` restored and md5-verified afterwards.

## Artifacts

vega12_dfini_null.c · build.sh · run.sh · build (in run.log header) ·
run.log · run.stability.log · fix_run.log · fix.diff · fix_build.log ·
env.txt · VERDICT.md · manifest.json · verdict.json
