Object-table walks dereference unvalidated VBIOS u16 offsets and stride unbounded/unchecked sizes β OOB kernel heap reads at attach (amdgpu twin of DF-3745)
Summary
get_connector_info_from_object_table walks display paths accumulating unvalidated per-entry usSize (up to ~16MB of pointer travel), encoder records at bios+data_offset+usRecordOffset with a ucRecordSize-stride walk terminating only on a non-conforming byte, router records + SrcDstTable derefs, connector records. parse_data_header does no extent validation and atom_context carries no bios_size, so every pointer runs past the kmalloced BIOS image. Crafted-VBIOS OOB heap reads at driver bind steering connector setup + page-fault DoS. table_end-bounding fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4152 Β· 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 | 4.3 KB | β raw |
| fix.diff | suggested-fix | Bound every object-table walk by the header-declared table end (bios+data_offset+size); validate each u16 offset deref and terminate record walks at the table end. | 3.9 KB | view raw |
| env.txt | environment | Guest uname + pciconf hardware-gate proof | 980 B | view raw |
DF-4152 β Object-table walks dereference unvalidated VBIOS offsets and stride unbounded sizes (amdgpu twin of DF-3745)
File: sys/dev/drm/amd/amdgpu/amdgpu_atombios.c (pass 2)
Reproduced?
No β hardware-gated. No AMD GPU on the audit guest (pciconf -l: only
virtio VGA 0x1111:1234; zero amdgpu/radeon matches in dmesg β env.txt).
Crafted-VBIOS delivery additionally requires romfile= VFIO assignment or a
malicious FPGA device. Established at source level.
Source trace (all inside amdgpu_atombios_get_connector_info_from_object_table, lines 291-563)
Enabler: amdgpu_atom_parse_data_header() (atom.c:1384-1403) returns
data_start = idx (a BIOS-supplied u16) with no extent validation, and
struct atom_context carries no bios_size β identical to the radeon
situation in DF-4104/DF-3745. The BIOS image itself is kmalloc(size) with
size from the ROM (amdgpu_bios.c:106/135/206). Every pointer of the form
bios + data_offset + <u16 from BIOS> is therefore an unvalidated heap
pointer.
-
Display-path walk (
:333-338):path_size += le16_to_cpu(path->usSize)accumulates per-entry u16 sizes with no cumulative bound;addrwalkspath_obj->asDispPath + path_size. 255 entries * 65535 = up to ~16 MB of pointer travel pastpath_obj(itself at an unvalidatedusDisplayPathTableOffset,:318-320). Each iteration dereferencespath->usSize/usDeviceTag/usConnObjectId/usGraphicObjIds[]β OOB heap reads of the parsed fields and of theusGraphicObjIds[j]inner loop (:375-386, count =(usSize-8)/2, unbounded). -
Encoder record deref + walk (
:392-410):record = bios + data_offset + enc_obj->asObjects[k].usRecordOffsetβ u16 offset, unvalidated β immediate OOB read ofrecord->ucRecordSize; thenwhile (ucRecordSize > 0 && ucRecordType > 0 && <= MAX)advances by the u8ucRecordSize. The walk terminates only when it reads a non-conforming byte β with a crafted BIOS the walk runs arbitrarily far past the allocation (min stride 1; each step needs size>0 and 1<=type<=ATOM_MAX_OBJECT_RECORD_NUMBER). Values read (e.g.ATOM_ENCODER_CAP_RECORD.usEncoderCap) feedamdgpu_display_add_encoder. -
Router record walk + src/dst table (
:416-482): same record-walk pattern (:420-422,:444-480), plusrouter_src_dst_table = bios + data_offset + usSrcDstTableOffset(:427-430) and thedst_objs[enum_id]walk bounded by the u8*num_dst_objs(:431-442) β both deref/stride unvalidated data. (TheucMuxState[enum_id]read within this block is the already-filed DF-1409; the offsets/walks feeding it are not covered by any known.) -
Connector record walk (
:491-541): identical deref ofcon_obj->asObjects[j].usRecordOffset(:495-502) anducRecordSizewalk (:507-538).
Related (same no-extent-check enabler, noted not separately filed): fixed
union firmware_info reads at bios+data_offset regardless of actual table
length (:588-713), and has_dce_engine_info's usDisplayPathTableOffset
deref (:280-288).
Distinction from knowns
- DF-1408 covers the
(size - sizeof(HEADER)) / sizeof(ENTRY)underflow sites (:106, :177, :926/945/967, :1326-1331) and the u8-count flex-array walks at:375/:389(enc_obj->ucNumberOfObjects,con_obj->ucNumberOfObjects). - DF-1409 covers
ucMuxState[enum_id]OOB. - Not covered (this finding): the unvalidated u16 offset dereferences
(
usRecordOffset,usSrcDstTableOffset,usDisplayPathTableOffset), theucRecordSize-stride record walks with no termination bound, and theusSizeaccumulation in the display-path walk.
Verdict
INCONCLUSIVE (hardware-gated / not reachable on the audit guest). Source-certain: crafted VBIOS β unbounded OOB kernel heap reads at driver attach / connector init (kheap disclosure ceiling is limited β parsed values steer encoder/connector/ddc setup β plus fault/DoS). Severity Medium, aligned with radeon twin DF-3745.
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 (four distinct walk vectors traced), fix.diff (table_end bounds), 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
Bound every object-table walk by the header-declared table end (bios+data_offset+size); validate each u16 offset deref and terminate record walks at the table end.
Verdict
INCONCLUSIVE (hardware-gated). amdgpu_atombios_get_connector_info_from_object_table (amdgpu_atombios.c:291-563) walks display paths by accumulating unvalidated usSize (up to ~16MB of pointer travel), dereferences encoder/router/connector usRecordOffset and usSrcDstTableOffset (u16, unvalidated), and strides record walks by ucRecordSize with no termination bound -- all past the kmalloced BIOS image at attach/connector init. amdgpu twin of DF-3745; parse_data_header does no extent validation and atom_context has no bios_size. Distinct from DF-1407/1408/1409 (count underflow / i2c_bus write / ucMuxState).
No comments yet.