# DF-4155 — `amdgpu_atombios_lookup_voltage_object_v3`: zero `usSize` strides forever; walk bounded only by an unvalidated `usStructureSize`

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_lookup_voltage_object_v3`, lines 1415-1430)

```c
u32 size = le16_to_cpu(v3->sHeader.usStructureSize);       /* BIOS u16, unvalidated */
u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
while (offset < size) {
        ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
        if (type/mode match) return vo;
        offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize);  /* may be 0 */
}
```

Two defects:

1. **Zero-stride infinite loop**: `usSize == 0` on the first (non-matching)
   voltage object ⇒ `offset` never advances ⇒ the loop re-reads the same
   header forever → hard hang. Callers: `amdgpu_atombios_get_svi2_info`
   (`:1452`), `amdgpu_atombios_is_voltage_gpio` (`:1494`), and
   `amdgpu_atombios_get_voltage_table` (`:1533`) — all invoked during
   amdgpu DPM init at driver bind with a crafted VBIOS. The radeon twin
   (`atom_lookup_voltage_object_v3`) is explicitly listed in DF-3741.

2. **Unvalidated bound**: the loop runs to `usStructureSize` (up to 65535),
   never against the actual BIOS allocation length (atom_context has no
   bios_size — DF-4104 enabler). A large claimed size makes the walk read
   up to ~64 KB past the `VoltageObjectInfo` table inside the kmalloced
   image → OOB kernel heap reads (headers, `ucVoltageType/Mode` comparisons)
   until a lucky match, the offset limit, or a fault.

Note the sibling `amdgpu_atombios_get_voltage_table` (`:1539-1540`) *does*
correctly clamp `ucGpioEntryNum > MAX_VOLTAGE_ENTRIES` (32) — the DF-1574/
DF-4003 count family is bounded at this site; only the lookup walk above is
defective.

## Verdict

INCONCLUSIVE (hardware-gated / not reachable on the audit guest).
Source-certain: deterministic hang via `usSize == 0`; OOB reads via
unvalidated `usStructureSize` walk bound. Severity Medium (crafted-VBIOS
DoS + OOB read at DPM init, 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.
