Integer underflow in radeon_atombios_get_asic_ss_info causes 1.4-billion-iteration OOB heap read
Summary
radeon_atombios_get_asic_ss_info at :1555/:1577: num_indices=(size-sizeof(HEADER))/sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2=12). size is u16 from BIOS. size<4 -> underflow to 0xFFFFFFFFFFFFFFFC/12=0x5555555555555555, truncates to int=1431655765. Loop iterates 1.4B times reading 12B per iteration past BIOS buffer into kernel heap -> panic on unmapped page or info leak. frev==2 and frev==3 (sizeof=12) affected. frev==1 (sizeof=10) and other tables (sizeof 4/8) produce negative int (loop skipped). Fix: validate size>=sizeof(HEADER) before subtraction.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1199 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | replica of (size-sizeof(HEADER))/sizeof(V2) underflow with real struct sizes | 3.0 KB | view raw |
| VERDICT.md | verdict | full narrative + fix (guard size>=sizeof(HEADER)) | 3.7 KB | β raw |
| build.sh | build-script | cc -O2 -Wall -o harness harness.c | 172 B | view raw |
| run.sh | run-script | ./harness | 66 B | view raw |
| run.log | run-log | underflow to 1431655765 for size 0..3 | 931 B | view raw |
| env.txt | environment | uname, cc version | 418 B | view raw |
| fix.diff | suggested-fix | guard size>=sizeof(ATOM_COMMON_TABLE_HEADER) before the switch | 704 B | view raw |
| fix_build.log | build-log | radeon.ko rebuilt with both radeon fixes, -Werror, rc=0 | 143.5 KB | view raw |
| README.md | readme | human reproduce doc | 1.4 KB | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1199 β radeon asic_ss_info size underflow -> OOB read loop
File: sys/dev/drm/radeon/radeon_atombios.c:1512-1578
Class: memory corruption (hardware/firmware-attacker; malicious CISS PCI device
or malicious VBIOS at driver attach). No local-unprivileged syscall trigger on the
audit guest (no HP Smart Array / no AMD GPU present).
Reproduce
./build.sh && ./run.sh
What the harness does
harness.c is a faithful userspace replica of the kernel parsing routine cited
above, fed crafted controller/VBIOS data that the real malicious device would
supply. It demonstrates the out-of-bounds access / overflow / underflow using the
real kernel macros and struct sizes, with a canary or computed-index check to
make the OOB observable without needing the hardware.
Expected output
A [BUG REPRODUCED] (or UNDERFLOW for DF-1199) marker plus the computed
out-of-range index / overflow byte count / underflowed loop count. See run.log
for the captured decisive run.
Fix
See fix.diff (git-apply-able) and VERDICT.md. The fix was validated to
compile (module rebuilt with -Werror) β see fix_build.log. No live-kernel
trigger exists on the guest, so the fix is validated at the
applies + compiles + closes-the-code-path level.
Artifacts
VERDICT.md (full narrative), harness.c, build.sh, run.sh,
run.log, env.txt, fix.diff, fix_build.log, manifest.json.
DF-1199 β radeon_atombios_get_asic_ss_info integer underflow (OOB read loop)
Verdict
REPRODUCED (harness) β real bug confirmed by source trace + userspace replica.
Impact class: integer underflow β ~12 GB out-of-bounds read loop over kernel
memory (panic on first unmapped page, or large info-leak of the BIOS/heap region
until it faults). No local-unprivileged trigger on the audit guest (no AMD GPU);
trigger requires a malicious VBIOS. uid=0 chain N/A β hardware/firmware-attacker
class; this is a read/DoS primitive (no write), so no escalation chain regardless.
Mechanism (confirmed path:line)
radeon_atombios_get_asic_ss_info() (sys/dev/drm/radeon/radeon_atombios.c)
computes a loop count from the BIOS-supplied table size:
sizeis declareduint16_t(radeon_atombios.c:1512), populated byatom_parse_data_header(... &size ...)(radeon_atombios.c:1528) from the BIOS table header'susStructureSize.num_indicesis declaredint(radeon_atombios.c:1516).radeon_atombios.c:1555-1556(frev==2),1577-1578(frev==3):num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
sizeof(ATOM_COMMON_TABLE_HEADER) = 4 (atombios.h:200-206: USHORT+UCHAR+
UCHAR); sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2) = 12. The subtraction is
performed in size_t (unsigned, 64-bit) because sizeof yields size_t, so
when size < 4 the uint16_t size is promoted and the subtraction wraps to
0xFFFFFFFF...FFC. Dividing by 12 gives 0x5555555555555555, which truncates
to int = 1431655765 (positive). The loop
for (i = 0; i < num_indices; i++) then iterates ~1.4 billion times, reading 12
bytes per iteration (ss_assign pointer arithmetic, radeon_atombios.c:1572-1573)
past the BIOS table into kernel memory β a DoS (panic on the first unmapped page)
or a large read of kernel/BIOS memory.
(For frev==1 the element size is 10 and the count would be negative as int, so
the loop is skipped β frev 2 and 3 are the affected paths.)
Harness proof (run.log)
harness.c reproduces the exact arithmetic with the real struct sizes:
size= 0 -> num_indices=1431655765 <-- UNDERFLOW (huge loop -> OOB read) size= 1 -> num_indices=1431655765 <-- UNDERFLOW (huge loop -> OOB read) size= 2 -> num_indices=1431655765 <-- UNDERFLOW (huge loop -> OOB read) size= 3 -> num_indices=1431655765 <-- UNDERFLOW (huge loop -> OOB read) size= 4 -> num_indices=0 size= 16 -> num_indices=1 size= 40 -> num_indices=3 Finding's cited value: size=2 -> num_indices=1431655765 (== 1431655765 ? YES) size_t trace: (2 - 4) = 0xfffffffffffffffe (18446744073709551614); /12 = 0x1555555555555555; trunc->int = 1431655765
Why not a live-kernel trigger / no uid0 chain
radeon attaches only to AMD/ATI Radeon PCIe GPUs (none on the guest). size
comes from the GPU VBIOS table header parsed at probe β not reachable from any
unprivileged syscall. Hardware/firmware-attacker class. Additionally this is a
read-only primitive (no write), so there is no memory-corruption escalation
chain to pursue even with hardware present β the impact ceiling is DoS / info
leak of the BIOS-adjacent kernel memory region.
Fix (fix.diff)
Validate size >= sizeof(ATOM_COMMON_TABLE_HEADER) once, before the switch
(frev), returning false if not (radeon_atombios.c:1533). This closes the
underflow for all three frev cases (1/2/3) with one guard. Matches the finding's
proposed fix (validate size >= sizeof(HEADER) before subtraction).
Fix validation
radeon.ko rebuilt from patched source (DF-1198/1199 applied) compiled with
-Werror and linked; radeon_atombios.o rebuilt. fix_status: not_testable
(no AMD GPU for a live trigger; validated applies + compiles + closes the path).
Fix verification
not_testablecompile+harness validated
module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
REPRODUCED (harness). radeon_atombios_get_asic_ss_info size<4 -> size_t underflow -> 1.4B iterations OOB read. radeon not in GENERIC.
No comments yet.