VRAM_Info MC-register-table path: unvalidated VBIOS NULL/offset/stride β NULL-deref panic, OOB read walk, and stride-0 infinite loop at attach
Summary
atomctrl_initialize_mc_reg_table dereferences the VRAM_Info table pointer without a NULL check, then feeds two walkers whose geometry is entirely VBIOS-controlled and never validated: an out-of-range offset starts an OOB read walk whose stride is attacker-chosen, and a zero stride with a non-matching tmem_id is a non-preemptible infinite loop in the kldload/attach path. Crafted VBIOS on CI/Iceland/Tonga: panic, hard hang, or OOB-read values programmed into memory-controller registers. NULL-check + validate-offset/stride fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4288 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.9 KB | β raw | |
| VERDICT.md | β | 4.1 KB | β raw | |
| fix.diff | β | 2.0 KB | view raw | |
| manifest.json | β | 1014 B | view raw | |
| verdict.json | β | 3.3 KB | view raw | |
| env.txt | β | 962 B | view raw |
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:
-
Missing NULL check β
vram_infois dereferenced atppatomctrl.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 thatamdgpu_atom_parse_data_headerfails, amdgpu/atom.c:1384-1403 β which performs no validation at all). Callersci_smumgr.c:2708,iceland_smumgr.c:2638,tonga_smumgr.c:3120run this during SMU backend init at driver attach. β NULL-deref kernel panic at boot/module-load with a VBIOS that omits VRAM_Info. -
Unvalidated
usMemClkPatchTblOffsetβppatomctrl.c:157-158computesreg_block = vram_info + le16(usMemClkPatchTblOffset)with a raw VBIOS USHORT, never checked against the table size returned bysmu_atom_get_data_table.atomctrl_set_mc_reg_address_table(ppatomctrl.c:102-131) then walksATOM_INIT_REG_INDEX_FORMATentries from that unchecked base (formatwalk at :117-127 readsucPreRegDataLengtheach step), andatomctrl_retrieve_ac_timingcomputesreg_data = reg_block + 4 + usRegIndexTblSize(ppatomctrl.c:55-56) βusRegIndexTblSizelikewise unvalidated. β arbitrary-offset OOB reads of kernel memory past the BIOS image (ctx->biosbuffer, amdgpu/atom.c), values copied intotable->mc_reg_table_entry[].mc_datawhich the caller later programs into memory-controller registers. -
Unbounded
reg_datawalk, attacker stride, stride 0 = infinite loop βatomctrl_retrieve_ac_timing(ppatomctrl.c:60-86) loopswhile (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK && num_ranges < 20), advancingreg_data += le16(usRegDataBlkSize)(:84-85). The loop boundnum_rangesonly increments when the moduleindexmatchestmem_id(:64). A VBIOS withusRegDataBlkSize == 0and a non-matchingtmem_idin 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 finalPP_ASSERTat :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).
DF-4288 VERDICT β VRAM_Info path unvalidated geometry
Status: inconclusive (code-trace certain; not runnable on guest β no AMD dGPU)
What was verified
Full read of sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c (1563 lines) and
every supporting definition/caller:
smu_atom_get_data_table()βsys/dev/drm/amd/powerplay/hwmgr/smu_helper.c:660-673: returnsNULLwheneveramdgpu_atom_parse_data_header()fails; the atom parser (sys/dev/drm/amd/amdgpu/atom.c:1384-1403) performs zero bounds validation β it trusts the VBIOS master-table offset (idx = CU16(...)) and returnsbios + data_startdirectly. Both*sizeand any innerusStructureSizeare raw VBIOS values.atomctrl_initialize_mc_reg_table()βppatomctrl.c:144-168:- :146
smu_atom_get_data_table(...VRAM_Info...)β result stored invram_info - :148
vram_info->ucNumOfVRAMModuledereferenced with no NULL check (contrast the guarded pattern used elsewhere in the same file, e.g. :494if (fw_info == NULL)and :614PP_ASSERT_WITH_CODE(NULL != table_address...)). - :157-158
reg_block = (uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset)β USHORT offset, never validated against the tablesize. atomctrl_set_mc_reg_address_table()βppatomctrl.c:102-131: walksATOM_INIT_REG_INDEX_FORMATentries from the uncheckedreg_blockbase; loop boundnum_entries = usRegIndexTblSize/sizeof(entry)(:107-108) is VBIOS-controlled; only guarded against exceeding the destination array (:113 num_entries <= VBIOS_MC_REGISTER_ARRAY_SIZE(32)), not against reading past the source table. (Note:111 num_entries--wraps 0β255 forusRegIndexTblSize < sizeof(entry), but 255 > 32 so the assert catches it β no bug there.)atomctrl_retrieve_ac_timing()βppatomctrl.c:48-93:- :55-56
reg_data = reg_block + 4 + le16(usRegIndexTblSize)β second unvalidated offset. - :60-86 walk: exit conditions are only the 0xFFFFFFFF sentinel word and
num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES(20);num_rangesincrements only on tmem_id match (:64-81).usRegDataBlkSize == 0+ non-matching index β infinite loop (same address re-read forever, non-preemptible kldload context). Non-matching index + any stride β walk continues past the BIOS image until a 0xFFFFFFFF word happens to appear (unbounded OOB read); :88 dereferences the final pointer again. - callers:
ci_smumgr.c:2708,iceland_smumgr.c:2638,tonga_smumgr.c:3120(*_initialize_mc_reg_tableduring SMU backend init at attach). - Destination-array bounds verified safe (so the bug is strictly an OOB
read/hang, not a write):
mc_reg_address[32]written fori < num_entries β€ 32(ppatomctrl.h:251);mc_reg_table_entry[20]indexed bynum_ranges < 20(ppatomctrl.h:250);mc_data[i-1]at i==0 (ppatomctrl.c:77-78) aliasesmclk_maxwithin the same struct (ppatomctrl.h:219-222) β in-bounds.
Why inconclusive (not not_reproduced)
The DragonFly QEMU guest used by this audit has no AMD dGPU (QEMU ships no
AMD GPU model; kldstat shows no drm modules β env.txt). The powerplay
attach path β the only reachable route into atomctrl_initialize_mc_reg_table β
cannot be entered, so no live PoC is possible in this environment. The
defects themselves are proven by trace; impact is boot/module-load kernel
panic (CWE-476), unbounded OOB read (CWE-125), or infinite-loop hang
(CWE-835) under a crafted VBIOS, i.e. the same threat model and severity
band as DF-1498 (Medium).
Exploit chain
None β this is a read-only/hang primitive in the DRM attach path, gated on attacker-controlled GPU firmware (physical supply-chain or malicious-reflash threat). No unprivileged-local or remote path exists to this code.
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.
Fix verification
not_testableBaseline behavior not reproducible on this guest (no AMD dGPU) -> no fixed-kernel build possible. fix.diff authored from trace.
findings/poc/DF-4288/fix.diff (not applied to sys/; authored post-verification from line-accurate trace)
Confirmed kernel references
- sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c:148
- sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c:157
- sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c:55
- sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c:60
- sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c:84
- sys/dev/drm/amd/powerplay/hwmgr/smu_helper.c:660
- sys/dev/drm/amd/amdgpu/atom.c:1384
Detail
Evidence (decisive lines)
VERDICT.md (line-by-line trace); README.md (defect summary + trigger shapes); fix.diff (NULL check + offset bound + stride/table bound); env.txt (guest lacks AMD GPU)
PoC changes
n/a β no PoC possible on this guest (no AMD dGPU); code-trace evidence pack instead
Verified recommended fix
NULL-check vram_info; validate usMemClkPatchTblOffset/usRegIndexTblSize/usRegDataBlkSize against the data-table size; reject usRegDataBlkSize < 4
Verdict
Three defects proven by code trace in the VRAM_Info -> MC-reg-table path of ppatomctrl.c: (1) vram_info from smu_atom_get_data_table is dereferenced at ppatomctrl.c:148 without a NULL check (helper returns NULL when the VBIOS master data table lacks VRAM_Info; the atom parser at amdgpu/atom.c:1384-1403 does no validation); (2) usMemClkPatchTblOffset (ppatomctrl.c:157) and usRegIndexTblSize (:55) are raw VBIOS USHORTs used as read offsets with no bound against the table size -> OOB read walk whose results are programmed into memory-controller registers; (3) atomctrl_retrieve_ac_timing's walk (:60-86) advances by VBIOS-controlled usRegDataBlkSize with num_ranges only incrementing on tmem_id match, so usRegDataBlkSize==0 with a non-matching index is a non-preemptible infinite loop in the kldload/attach path (CWE-835), and a missing 0xFFFFFFFF sentinel walks past the BIOS image unbounded (CWE-125). Impact is boot/module-load kernel panic or hang under a crafted VBIOS β same threat model and Medium band as the known DF-1498. NOT runnable on this audit guest: it has no AMD dGPU (QEMU has no AMD GPU model; no drm module loads β env.txt), so the powerplay attach path cannot be entered; verification is by exhaustive trace (VERDICT.md). Destination arrays verified in-bounds, so no write primitive: mc_reg_address[32] indexed < 32 (ppatomctrl.h:251), mc_reg_table_entry[20] indexed < 20 (:250), mc_data[i-1] at i==0 aliases mclk_max in-struct (ppatomctrl.h:219-222).
No comments yet.