# DF-4545 — vega20 pptable init reports SUCCESS with NULL OD arrays → NULL-deref panic at driver load

**Severity: Medium (crafted-VBIOS deterministic kernel panic) | Confidence: certain**
**File: `sys/dev/drm/amd/powerplay/hwmgr/vega20_processpptables.c:823,835-846,870-877,880-891`**

## What

Two independent gaps leave `hwmgr->pptable->od_feature_capabilities` /
`od_settings_max` / `od_settings_min` NULL while
`vega20_pp_tables_initialize()` returns **0 (success)**:

1. **The revision gate** (:823): the three OD copies run only when
   `OverDrive8Table.ucODTableRevision == 1`. Any other legal value (0, 2,
   3, ...) skips them entirely — no error, arrays stay NULL. The
   PowerSaving clock copies (:864-878) have the same shape.
2. **Ignored return codes** (CWE-252): the five copy calls
   (:835-846, :870-877) drop `-ENOMEM` on the floor, so an allocation
   failure also yields NULL arrays with a "successful" init.

`vega20_pp_tables_initialize` (hwmgr.c:222) runs before `backend_init`
(hwmgr.c:229); `vega20_hwmgr_backend_init` → `vega20_enable_dpm_tasks` →
`vega20_od8_initialize_default_settings` (vega20_hwmgr.c:1598) →
`vega20_od8_set_feature_capabilities`, whose **first** array access
(vega20_hwmgr.c:906, `od_feature_capabilities[0]` with
`GNLD_DPM_GFXCLK` enabled on real silicon) dereferences NULL → kernel
panic during amdgpu driver load. The fill loop (:1219) would deref NULL
likewise.

Same untrusted-firmware threat model as knowns DF-1689/DF-1690 but a
different defect class (NULL deref / skipped-init-reported-as-success vs
OOB read of the blob). Note also :857 reads
`ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]` unconditionally even
when the revision gate skipped parsing — garbage TDPODLimit can set the
PowerControl cap.

## Reproduce (lifted-copy harness)

```
./build.sh && ./run.sh
```

Expected (run.log):
- CONTROL rev=1 healthy alloc → init SUCCESS, consumer completes, no fault
- VARIANT A crafted `ucODTableRevision=2` → check_powerplay_tables PASSES
  (format rev 11, structuresize>0, smcPPTable.Version=3), init returns 0
  with `od_feature_capabilities=0x0`, consumer faults:
  **SIGSEGV at address 0x0** — panic-class
- VARIANT B rev=1 + injected kzalloc failure (the ignored -ENOMEM) → same
  fault at 0x0
- PATCHED (fix.diff: checked returns + refuse-to-succeed-with-NULL) → init
  returns -EINVAL, consumer never runs, no fault

## Fix validation

- `fix.diff` — `git apply --check` OK; return codes checked + NULL guard
  that fails init with -EINVAL
- full `amdgpu.ko` rebuild with the patch under the real kernel toolchain
  (**-Werror**): RC=0 (fix_build.log); guest /usr/src restored
- harness PATCHED control: crafted rev=2 refused at init, no fault

## Files
- `od_null_deref.c` (sha256
  97242d7d577fb00d2cc1ea71b6a54a0758c8caa2a5df42f3b659601a1fac0739)
- `build.sh` / `run.sh`, `build.log` / `run.log` / `run.2.log` / `fix_run.log`
- `fix.diff`, `fix_build.log`, `env.txt`, `VERDICT.md`, `manifest.json`, `verdict.json`
