SS-assignment walk bounded only by the table's own usStructureSize β up to 64KB OOB read past the ATOM table
Summary
The SS-assignment walk is bounded solely by the VBIOS-controlled usStructureSize header, never validated against the actual table/ROM extent - the size the data-table lookup returns is the SAME header field, so it cannot bound the walk either. A crafted oversized header walks past the BIOS image reading from adjacent kernel heap until an unmapped page faults or a coincidental match stops it. The fix must validate idx+size against the ROM image length in the atom layer - which this tree's atom_context cannot even express (no bios_size member). Bios-length plumbing fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4289 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.7 KB | β raw | |
| VERDICT.md | β | 2.8 KB | β raw | |
| fix.diff | β | 2.0 KB | view raw | |
| manifest.json | β | 795 B | view raw | |
| verdict.json | β | 2.8 KB | view raw | |
| env.txt | β | 962 B | view raw |
DF-4289 β SS-assignment walk bounded only by unvalidated VBIOS usStructureSize β OOB read (β€64 KB past ATOM table)
Pass-2 finding for sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c.
Distinct from DF-1498 (ASIC_ProfilingInfo leakage arrays): this is the
ASIC_InternalSS_Info walk in asic_internal_ss_get_ss_asignment()
feeding atomctrl_get_engine_clock_spread_spectrum() /
atomctrl_get_memory_clock_spread_spectrum().
The bug (ppatomctrl.c:1231-1243)
ssInfo = &table->asSpreadSpectrum[0];
while (((uint8_t *)ssInfo - (uint8_t *)table) <
le16_to_cpu(table->sHeader.usStructureSize)) {
if ((clockSource == ssInfo->ucClockIndication) && ...)
break;
ssInfo = (ATOM_ASIC_SS_ASSIGNMENT *)((uint8_t *)ssInfo +
sizeof(ATOM_ASIC_SS_ASSIGNMENT));
}
tablecomes fromsmu_atom_get_data_table(..., &size, ...)(ppatomctrl.c:1204-1207). The atom layer returns a raw pointer into the BIOS image (bios + data_start) and itssize/usStructureSizeare VBIOS-controlled;amdgpu_atom_parse_data_header(sys/dev/drm/amd/amdgpu/atom.c:1384-1403) validates nothing.- The only loop bound is
usStructureSizeβ the table's own header field β never checked against the actual allocated table size. A VBIOS withusStructureSize(USHORT) larger than the real table walksATOM_ASIC_SS_ASSIGNMENT(10-byte) entries past the end of the BIOS image: up to 65535 bytes past the table base, dereferencingucClockIndicationandulTargetClockRangeeach step (OOB read, CWE-125). On x86-64 kernel heap that is adjacent-kernel-memory read until an unmapped page or a coincidental match stops it; the values are then copied intossEntry(speed_spectrum_percentage,speed_spectrum_rate) and used to program spread-spectrum PLL registers by the callers (ci/iceland/fiji/tonga/vegam smumgr).
Callers (attach-time, chip-specific)
atomctrl_get_engine_clock_spread_spectrum β ci_smumgr.c:343,
iceland_smumgr.c:843; atomctrl_get_memory_clock_spread_spectrum β
ci_smumgr.c:1084, iceland_smumgr.c:~1090 family β all during SMC table
construction at driver attach.
Threat model
Crafted VBIOS on an AMD dGPU (same as DF-1498): boot/module-load OOB read of adjacent kernel heap (bounded 64 KB), potential panic on unmapped page, or silent programming of garbage SS parameters.
Reproduce
Not runnable on this guest (no AMD dGPU β env.txt). Trigger shape on
hardware: ASIC_InternalSS_Info table whose header usStructureSize
exceeds the table's actual size with no entry matching the requested
clockSource. Expected: OOB read walk / eventual Fatal trap 12 on
unmapped page during attach.
DF-4289 VERDICT β SS-assignment OOB walk
Status: inconclusive (code-trace certain; guest has no AMD dGPU)
Trace
asic_internal_ss_get_ss_asignment()β ppatomctrl.c:1215-1273.- :1226-1229 table =
asic_internal_ss_get_ss_table(hwmgr->adev); NULL-checked. - :1204-1207 the table is
smu_atom_get_data_table(..., &size, &frev, &crev)βsizeis fetched but never used anywhere in the function. - :1231-1243 walk bound is exclusively
le16_to_cpu(table->sHeader.usStructureSize)β a field inside the (attacker-supplied) table content, not the atom-layer table size. - Each iteration reads
ssInfo->ucClockIndication(:1235) andssInfo->ulTargetClockRange(:1236) β reads happen at the current offset before the bound is re-checked, so ausStructureSizelarger than the real table immediately reads past it; stridesizeof(ATOM_ASIC_SS_ASSIGNMENT)(fixed), max excursion β€ 0xFFFF bytes. - Atom layer (
sys/dev/drm/amd/amdgpu/atom.c:1384-1403):amdgpu_atom_parse_data_header()performs no validation ofidx,*size, or the bios buffer bounds;smu_atom_get_data_table(smu_helper.c:660-673) passes the raw pointer through. - Exit conditions: match on (clockSource, clockSpeed β€ ulTargetClockRange) or bound reached. Non-matching crafted table β full 64 KB excursion.
- Output
ssEntryfields (:1246-1254):speed_spectrum_percentage,speed_spectrum_rate(raw VBIOS USHORT, and for table rev β₯ 2.2/3 divided by the constant 100 at :1253 β see DF-4290 for the div0 that this value feeds),speed_spectrum_mode. These are consumed by ci_smumgr.c:343-356 / :1084-1092 and equivalents in iceland/fiji/tonga/vegam smumgr to program CG_SPLL_SPREAD_SPECTRUM / MPLL_SS registers.
Bound check on the other dimension (verified safe)
The fixed-stride walk starts at offsetof(ATOM_ASIC_INTERNAL_SS_INFO,
asSpreadSpectrum[0]) and the bound is checked before each iteration's
reads, so for a correct usStructureSize there is no OOB; the defect is
solely the unvalidated upper bound. No write occurs (pure read walk +
copy-out into the caller's pp_atomctrl_internal_ss_info).
Impact
Boot/module-load OOB read of adjacent kernel heap (CWE-125), panic on unmapped page possible, or programming of garbage PLL/SS register values (hardware-stability impact). Crafted-VBIOS threat model β Medium, consistent with DF-1498. Not runnable on this guest (no AMD dGPU) β inconclusive status, trace-certain.
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-4289/fix.diff (not applied to sys/; authored post-verification from line-accurate trace)
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (trace incl. the size==usStructureSize identity); README.md; fix.diff (atom.c ROM-bounds validation + bios_size plumbing); env.txt
PoC changes
n/a β no AMD dGPU on guest; code-trace evidence pack
Verified recommended fix
Track BIOS image length in atom_context and reject data tables whose idx+size exceed it in amdgpu_atom_parse_data_header
Verdict
asic_internal_ss_get_ss_asignment() (ppatomctrl.c:1215-1273) bounds its ATOM_ASIC_SS_ASSIGNMENT walk solely by the table header's usStructureSize (ppatomctrl.c:1233-1234) β a VBIOS-controlled USHORT that is never validated against the actual data-table/ROM extent (amdgpu_atom_parse_data_header, sys/dev/drm/amd/amdgpu/atom.c:1384-1403, performs no validation and struct atom_context does not even track the BIOS image length). A crafted ASIC_InternalSS_Info table with an oversized usStructureSize and no matching ucClockIndication walks the fixed 10-byte stride past the end of the BIOS image, reading ucClockIndication/ulTargetClockRange from adjacent kernel heap for up to 65535 bytes (CWE-125); results are programmed into CG_SPLL/MPLL spread-spectrum registers by the ci/iceland/fiji/tonga/vegam smumgr callers at attach. Note: the size returned by smu_atom_get_data_table IS usStructureSize (same header field), so the existing fetch-and-ignore of size cannot bound the walk β the fix must live in the atom layer (validate idx+size <= ROM length), which is what fix.diff implements. Same crafted-VBIOS threat model and Medium band as DF-1498. NOT runnable on this guest (no AMD dGPU; no drm module loads β env.txt); trace-certain.
No comments yet.