Unvalidated VBIOS container offsets in r600_parse_extended_power_table: usFanTableOffset and usExtendendedHeaderOffset dereferenced with no zero/bounds check β offset 0 aliases the PowerPlayInfo header as the extended header; out-of-range offsets read past the kmalloc'd BIOS image (sibling of DF-1566: offset provenance, not counts)
Summary
All six sub-table offsets inside the extended header are checked for non-zero, but the two container offsets are not checked at all: the fan-table pointer accepts any u16 offset past the end of the kmalloc'd BIOS buffer, and ext_hdr is dereferenced with no validation - offset 0 reads the PowerPlayInfo header as the extended header, turning all six downstream table offsets into garbage pointing outside small ROMs. No ROM size is plumbed anywhere in the radeon driver (the shared root of the atom.c DF-4337 radeon-side assessment). Plumb bios_size + validate fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4372 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.8 KB | β raw | |
| VERDICT.md | β | 3.2 KB | β raw | |
| fix.diff | β | 5.3 KB | view raw | |
| manifest.json | β | 1.1 KB | view raw | |
| verdict.json | β | 2.3 KB | view raw |
DF-4372 β r600_parse_extended_power_table dereferences two VBIOS offsets
without any validation (fan table offset, extended-header offset)
- File:
sys/dev/drm/radeon/r600_dpm.c(:891-918 fan table, :1068-1073 ext header + every downstream ext-table condition) - Severity: Low (sibling of DF-1566 β distinct missing checks: offset provenance rather than count/index bounds; same hostile-VBIOS threat)
- Class: CWE-125 / CWE-20 (unvalidated firmware offset β OOB heap reads and pointer confusion of the entire extended-table parse).
The bug
Every sub-table inside the extended header checks its own offset field
(usVCETableOffset, usUVDTableOffset, β¦) for non-zero, but the two
container offsets are used with no check at all:
-
Fan table β
r600_dpm.c:893-895:fan_info = bios + data_offset + usFanTableOffsetand immediately dereferenced (ucTHyst,usTMin, β¦, and forucFanTableFormat >= 2thefan2/fan3unions at :903-915).usFanTableOffsetis a raw u16 from the ROM: 0 is pre-checked, but any value up to 65535 is accepted even whendata_offset + offset(+ record size) lies beyond the kmalloc'd BIOS image (radeon_bios.c:68/98/153/269/717, β€ 256 KiB) β OOB heap read; withucFanTableFormatitself read out of bounds the walk can chain further. -
Extended header β
r600_dpm.c:1070-1073:ext_hdr = bios + data_offset + usExtendendedHeaderOffsetis dereferenced (ext_hdr->usSize) with no zero check and no bound. A crafted table withusExtendendedHeaderOffset == 0aliases the PowerPlayInfo table header itself as the extended header:usSizeand all six sub-table offsets then come from unrelated header fields, and each subsequentext_hdr->usXTableOffset(used at :1074-1293 for VCE/UVD/SAMU/PPM/ACP/ PowerTune) can point anywhere within a 64 KiB window ofbiosβ far outside the actual allocation on small ROMs. The downstream count/index walks are DF-1566's known territory; the pointer provenance itself is unchecked here.
Trigger
Crafted VBIOS on a radeon DPM-family card (modified ROM dump, hostile
option ROM, or ACPI VFCT image β radeon_bios.c:717 copies the VFCT image
into the same kmalloc buffer). Boot β radeon attach β radeon_pm_init β
<asic>_dpm_init β r600_parse_extended_power_table.
Fix
fix.diff plumbs the real ROM size (rdev->bios_size, set at every
allocation site in radeon_bios.c) into the parser and (a) rejects a fan
table offset that runs past the image, (b) computes ext_hdr only when
usExtendendedHeaderOffset != 0 and data_offset + ext_off +
sizeof(ATOM_PPLIB_EXTENDEDHEADER) <= bios_size, gating all six downstream
conditions on the result (ext_hdr_ok). Verified patch -p1 --dry-run β
APPLIES_CLEAN on scratch copies (radeon.h, radeon_bios.c, r600_dpm.c).
DF-4372 VERDICT β unchecked fan/ext-header offsets in r600_parse_extended_power_table
Bottom line
Certain by static proof; PoC phase not executed (Low severity, and the audit VM has no radeon GPU / no /dev/dri). Two container offsets from the VBIOS are dereferenced with no zero/bounds validation, distinct from the count/index walks already covered by DF-1566.
Detail
r600_dpm.c:893-895βfan_infoderived fromusFanTableOffset(u16) and dereferenced at :896-915, including the versioned union reads (fan2.usTMaxat :904,fan3.ucFanControlMode/usFanPWMMax/usFanOutputSensitivityat :909-914) whose format byte (ucFanTableFormat) itself comes from the same unvalidated location.r600_dpm.c:1070-1073βext_hdrderived fromusExtendendedHeaderOffsetwith no check whatsoever: offset 0 reads the PowerPlayInfo header as the extended header (in-bounds but wrong object β all derived sub-table offsets become header garbage); an offset beyond the image reads off the end of the β€256 KiBrdev->bioskmalloc buffer. Six downstream blocks (:1074-1293) then chase the garbage offsets; their internal count/index behavior is DF-1566 (not re-reported).atom_parse_data_header()(atom.c) already returns an unboundeddata_offset(noted in DF-1566); the container-offset checks added by this finding's fix close the remaining provenance holes inside this parser.
Threat model / impact
Requires control of the GPU VBIOS (physically modified card, option-ROM
injection, or ACPI VFCT image at radeon_bios.c:717). Impact: OOB kernel
heap reads (values copied into rdev->pm.dpm.fan.* and dyn_state tables,
potentially observable via hwmon/debugfs on some setups) and mis-programmed
fan/voltage behavior. Consistent with DF-1566's Medium rating for the
stronger count-walk variant; the offset-provenance half is narrower β Low.
Verification on the audit VM
Not attempted at runtime: no radeon hardware (QEMU virtio VGA only), no
/dev/dri, VBIOS not attacker-controllable in this VM. Status untested,
impact none on this guest; the code defect itself is certain from
inspection.
Fix validation
fix.diff (3 files: radeon.h adds bios_size; radeon_bios.c records it at
all five allocation sites :68/:98/:153/:269/:717; r600_dpm.c validates both
offsets and gates the six ext-table conditions on ext_hdr_ok). Verified
patch -p1 --dry-run β APPLIES_CLEAN on scratch copies. Runtime validation
impossible on this VM β fix_status: not_testable.
kernel_refs
- sys/dev/drm/radeon/r600_dpm.c:893-915 (fan table walk)
- sys/dev/drm/radeon/r600_dpm.c:1070-1073 (ext_hdr deref, no checks)
- sys/dev/drm/radeon/r600_dpm.c:1074-1293 (six ext-table consumers)
- sys/dev/drm/radeon/radeon_bios.c:68,98,153,269,717 (bios allocation, β€256 KiB)
- sys/dev/drm/radeon/radeon.h:2333 (*bios field)
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.diff authored post-verification (radeon.h + radeon_bios.c + r600_dpm.c); applies cleanly via patch -p1 --dry-run on scratch copies; runtime validation impossible on this VM (no radeon hardware)
findings/poc/DF-4372/fix.diff; dry-run output 'checking file ... radeon.h / radeon_bios.c / r600_dpm.c / DF4372_APPLIES_CLEAN'
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md; README.md; fix.diff (3-file) verified APPLIES_CLEAN
PoC changes
none (no runnable PoC possible without radeon hardware and a crafted VBIOS)
Verified recommended fix
Plumb rdev->bios_size from the allocation sites and validate usFanTableOffset / usExtendendedHeaderOffset (non-zero, within image) before any dereference; gate all six ext-table blocks on the validated header (see fix.diff)
Verdict
PoC phase not executed for this Low-severity finding (per audit contract PoC is optional below Medium; additionally the audit VM has no radeon GPU, no /dev/dri, and the VBIOS is not attacker-controllable in a QEMU virtio-gpu VM). Defect is certain from inspection: r600_parse_extended_power_table dereferences usFanTableOffset (r600_dpm.c:893-895, versioned union reads :903-915) and usExtendendedHeaderOffset (r600_dpm.c:1070-1073) with no zero/bounds validation; offset 0 aliases the PowerPlayInfo header as the extended header and out-of-range offsets read past the <=256KiB kmalloc'd BIOS image. Sibling of DF-1566 (which covers the count/index walks); this covers the container-offset provenance.
No comments yet.