amdgpu_atombios_init_mc_reg_table: zero-stride reg_data walk never terminates; unbounded block walk and unvalidated offsets read past the VBIOS buffer (amdgpu twin of DF-3741)
Summary
In the VRAM_Info v2_1 parser, the block walk advances reg_data by BIOS u16 usRegDataBlkSize; when the stride is 0 and the mem-id never matches, the only exits never fire - deterministic infinite loop at DPM init. With a small non-zero stride and no END marker the walk marches past the kmalloced BIOS image (inner loop reads up to 32 dwords per block) until a lucky 0xFFFFFFFF or a fault. usMemClkPatchTblOffset/usRegIndexTblSize dereferenced unvalidated. Write side correctly clamped. Reject-zero-stride + table_end fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4154 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| vbios_mutator.py | trigger | Illustrative trigger (hardware-gated) | 1.5 KB | view raw |
| VERDICT.md | verdict | Full source-trace analysis | 3.0 KB | β raw |
| fix.diff | suggested-fix | Reject usRegDataBlkSize==0 and bound every reg_data step (and the inner j reads) by the declared VRAM_Info table end. | 2.3 KB | view raw |
| env.txt | environment | Guest uname + pciconf hardware-gate proof | 980 B | view raw |
DF-4154 β amdgpu_atombios_init_mc_reg_table: zero-stride block walk never terminates; unbounded walk + unvalidated offsets read past the VBIOS buffer (amdgpu twin of DF-3741)
File: sys/dev/drm/amd/amdgpu/amdgpu_atombios.c (pass 2)
Reproduced?
No β hardware-gated (no AMD GPU on the audit guest; see env.txt).
Established at source level.
Source trace (amdgpu_atombios_init_mc_reg_table, lines 1583-1672)
Called from the DPM init paths (si/kv/ci) with a module_index; parses
VRAM_Info v2_1:
-
Unvalidated derefs:
reg_block = (u8*)vram_info + usMemClkPatchTblOffset(:1607-1609) andreg_data = reg_block + 4 + usRegIndexTblSize(:1610-1613) β both u16 BIOS values used as pointer offsets from a table whose extent is never validated (DF-4104 enabler) β OOB reads before the loop even starts.num_entriesis (correctly) clamped toVBIOS_MC_REGISTER_ARRAY_SIZE(32) at:1617-1618, and the destination arrays (mc_reg_address[32],mc_reg_table_entry[20]) are respected β the write side is fine; it is the walk that is unbounded. -
Zero-stride infinite loop (
:1631-1653):
while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&
(num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
t_mem_id = (*(u32 *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT;
if (module_index == t_mem_id) { ...; num_ranges++; }
reg_data += le16_to_cpu(reg_block->usRegDataBlkSize); /* may be 0 */
}
The only exits are reading END_OF_REG_DATA_BLOCK (0xFFFFFFFF) or
num_ranges == 20. num_ranges increments only when the block's mem id
matches. Crafted usRegDataBlkSize == 0 + first dword != 0xFFFFFFFF +
t_mem_id != module_index β the loop spins forever on the same word β
kernel hang at DPM init (uninterruptible, IRQ-context-free but boot-path/
bind-path wedge). Identical shape to radeon's radeon_atom_init_mc_reg_table
in DF-3741.
- Unbounded OOB read walk: with a small non-zero stride and no END
marker inside the buffer,
reg_datamarches past thekmalloced BIOS image reading*(u32*)reg_dataeach step (and the inner:1639-1648loop reads((u32*)reg_data + j)forj < reg_table->last, β€ 32 extra words per block) until it happens to hit 0xFFFFFFFF in adjacent heap or faults. Values land inreg_table->mc_reg_table_entry[]and are later programmed into MC registers.
Verdict
INCONCLUSIVE (hardware-gated / not reachable on the audit guest).
Source-certain: (a) deterministic infinite loop on usRegDataBlkSize == 0,
(b) unbounded OOB reads of the kernel heap past the BIOS allocation, from a
crafted VBIOS at driver bind/DPM init. Severity Medium (DoS + OOB read,
hardware-gated).
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_testableFix not testable: single-fix kernel build cannot exercise adv(4)/amdgpu paths without the respective hardware on the guest.
fix.diff authored post-verification from line-accurate source trace (VERDICT.md); env.txt documents absent hardware.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (loop-exit analysis), fix.diff (stride+extent checks), env.txt (guest has no AMD GPU).
PoC changes
Seed replaced with an honest hardware-gated trigger sketch/mutator; no runnable PoC exists for this defect class on the audit guest.
Verified recommended fix
Reject usRegDataBlkSize==0 and bound every reg_data step (and the inner j reads) by the declared VRAM_Info table end.
Verdict
INCONCLUSIVE (hardware-gated). amdgpu_atombios_init_mc_reg_table (amdgpu_atombios.c:1583-1672): (a) usRegDataBlkSize==0 with non-matching t_mem_id makes the block walk at :1631-1653 spin forever (num_ranges never increments, no other exit) -> kernel hang at DPM init; (b) the walk is bounded by nothing but a lucky 0xFFFFFFFF read -- unbounded OOB heap reads past the BIOS allocation (inner loop reads ((u32*)reg_data)+j too); (c) usMemClkPatchTblOffset/usRegIndexTblSize derefs unvalidated. amdgpu twin of DF-3741. Write side is properly clamped (:1617).
No comments yet.