# DF-4288 — VRAM_Info/MC-register-table path: missing NULL check + fully unvalidated VBIOS offsets/strides (OOB read walk, stride-0 infinite loop)

Pass-2 finding for `sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c`.
Not the known DF-1496/1497/1498 (those cover `atomctrl_get_smc_sclk_range_table`
count overflow, `atomctrl_get_svi2_info` lookup NULL, and the
ASIC_ProfilingInfo leakage arrays). This pack covers the **VRAM_Info →
MC-register-table** path that was not audited in pass 1.

## The bug (three defects, one path)

`atomctrl_initialize_mc_reg_table()` (ppatomctrl.c:133-168) fetches the
VBIOS `VRAM_Info` data table and feeds it to two walkers:

1. **Missing NULL check** — `vram_info` is dereferenced at
   `ppatomctrl.c:148` (`vram_info->ucNumOfVRAMModule`) with no NULL check.
   `smu_atom_get_data_table()` (smu_helper.c:660-673) returns NULL when the
   master data table has no VRAM_Info entry (or the master table itself is
   malformed such that `amdgpu_atom_parse_data_header` fails,
   amdgpu/atom.c:1384-1403 — which performs **no** validation at all).
   Callers `ci_smumgr.c:2708`, `iceland_smumgr.c:2638`, `tonga_smumgr.c:3120`
   run this during SMU backend init at driver attach.
   → NULL-deref kernel panic at boot/module-load with a VBIOS that omits
   VRAM_Info.

2. **Unvalidated `usMemClkPatchTblOffset`** — `ppatomctrl.c:157-158`
   computes `reg_block = vram_info + le16(usMemClkPatchTblOffset)` with a
   raw VBIOS USHORT, never checked against the table size returned by
   `smu_atom_get_data_table`. `atomctrl_set_mc_reg_address_table`
   (ppatomctrl.c:102-131) then walks `ATOM_INIT_REG_INDEX_FORMAT` entries
   from that unchecked base (`format` walk at :117-127 reads
   `ucPreRegDataLength` each step), and `atomctrl_retrieve_ac_timing`
   computes `reg_data = reg_block + 4 + usRegIndexTblSize`
   (ppatomctrl.c:55-56) — `usRegIndexTblSize` likewise unvalidated.
   → arbitrary-offset OOB reads of kernel memory past the BIOS image
   (`ctx->bios` buffer, amdgpu/atom.c), values copied into
   `table->mc_reg_table_entry[].mc_data` which the caller later programs
   into memory-controller registers.

3. **Unbounded `reg_data` walk, attacker stride, stride 0 = infinite loop**
   — `atomctrl_retrieve_ac_timing` (ppatomctrl.c:60-86) loops
   `while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK && num_ranges < 20)`,
   advancing `reg_data += le16(usRegDataBlkSize)` (:84-85). The loop bound
   `num_ranges` only increments when the module `index` matches `tmem_id`
   (:64). A VBIOS with `usRegDataBlkSize == 0` and a non-matching
   `tmem_id` in the first word loops **forever** (same address, no
   progress, no lock drop) — hard hang of the kldload/attach thread.
   A nonzero stride with no END marker (0xFFFFFFFF word) walks past the
   BIOS image indefinitely until it happens to find one (OOB read of
   arbitrary length). The final `PP_ASSERT` at :88 also dereferences the
   walked-off pointer.

## Threat model

Crafted VBIOS on an AMD dGPU (malicious/exploited GPU firmware or EEPROM
reflash) — the standard powerplay threat model of this audit (same as
DF-1496/1497/1498). Boot-time/module-load kernel DoS: NULL-deref panic,
unbounded OOB read, or non-preemptible infinite loop in the DRM attach
path.

## Reproduce

Not runnable on this audit guest: it has no AMD dGPU (QEMU exposes no
AMD GPU model; no drm modules load — see `env.txt`), so the powerplay
attach path cannot be entered. Verification is by exhaustive code trace
(VERDICT.md + trace.md). On hardware (or with a VBIOSimage fuzz harness
driving `amdgpu_atom_parse_data_header` directly) the trigger is:
VRAM_Info table absent (defect 1), or
`usMemClkPatchTblOffset`/`usRegIndexTblSize` beyond table end (defect 2),
or `usRegDataBlkSize=0` with mismatched `ucMemClkPatchTbl` tmem_id
(defect 3).

Expected: `Fatal trap 12` NULL deref (defect 1), garbage MC register
programming / eventual fault (defect 2), or attach thread spinning at
100% forever (defect 3).
