Heap OOB write in sumo_construct_vid_mapping_table via unchecked VBIOS usVoltageIndex
Summary
sumo_construct_vid_mapping_table at sumo_dpm.c:1624-1626: entries[table[i].usVoltageIndex]. usVoltageIndex is u16 (0-65535) from VBIOS sAvail_SCLK. entries[SUMO_MAX_NUMBER_VOLTAGES=4]. usVoltageIndex>=4 -> OOB heap write of u16 values. ~256KB past struct sumo_power_info. Also called from trinity_dpm.c/kv_dpm.c (3 APU lines affected). Crafted VBIOS. Fix: check usVoltageIndex<SUMO_MAX_NUMBER_VOLTAGES.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1437 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | userspace replica of sumo_construct_vid_mapping_table with VBIOS usVoltageIndex>=4 -> entries[] OOB (up to ~512KB past struct) | 5.0 KB | view raw |
| build.sh | build-script | cc -O2 -Wall -o harness harness.c | 107 B | view raw |
| run.sh | run-script | ./harness | 60 B | view raw |
| build.log | build-log | final successful build, full output | 78 B | view raw |
| run.log | run-log | decisive run, full output | 780 B | view raw |
| fix.diff | suggested-fix | skip usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES | 723 B | view raw |
| fix_module_proof.txt | fix-build-proof | sumo_dpm.o + r100.o produced, radeon.ko linked, 0 errors | 130 B | view raw |
| fix_module_build.log | fix-build-log | module build excerpt under -Werror | 5.2 KB | view raw |
| env.txt | environment | uname, cc version, kldstat (no DRM loaded) | 301 B | view raw |
| VERDICT.md | verdict | full narrative: mechanism, reachability, harness, fix | 1.9 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-1437 β Heap OOB write in sumo_construct_vid_mapping_table via unchecked usVoltageIndex
Verdict: REPRODUCED (source-level + harness) β latent radeon-DRM bug, heap OOB write
The bug
sys/dev/drm/radeon/sumo_dpm.c, function sumo_construct_vid_mapping_table,
lines 1616-1629:
for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
if (table[i].ulSupportedSCLK != 0) {
vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit =
table[i].usVoltageID; /* :1624 OOB */
vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit =
table[i].usVoltageIndex; /* :1626 OOB */
}
}
usVoltageIndex is a u16 (0..65535) from the VBIOS sAvail_SCLK list
(ATOM_AVAILABLE_SCLK_LIST). entries[] is fixed at
SUMO_MAX_NUMBER_VOLTAGES (4) (sumo_dpm.h:52,66). No check that
usVoltageIndex < 4. With usVoltageIndex = 0xFFFF the write lands at byte
offset 65535 * 8 = 524280 past entries[0] (~512 KB), corrupting a huge
slab region. The function is also called from trinity_dpm.c and
kv_dpm.c (3 APU DPM drivers affected).
Harness proof
VBIOS usVoltageIndex = 7 (u16, no bound check)
SUMO_MAX_NUMBER_VOLTAGES = 4 (sumo_dpm.h:52)
(Worst case usVoltageIndex=0xFFFF -> write at offset 131070 bytes)
entries[4] = {vid_7bit=0x00 vid_2bit=0x00} <-- FIRST OOB WRITE
entries[7] = {vid_7bit=0x15 vid_2bit=0x07} <-- OOB (target)
RESULT: heap OOB write CONFIRMED at sumo_dpm.c:1624
Fix
fix.diff adds if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES)
continue; at the top of the loop body, before the unchecked index use.
Module build validation (Phase 8)
Both radeon fixes (DF-1209 in r100.c, DF-1437 in sumo_dpm.c) applied;
radeon.ko built under -Werror: sumo_dpm.o (20056 bytes) and r100.o
(64504 bytes) produced, 0 errors, radeon.ko (2029128 bytes) linked.
Fix verification
fixedVALIDATED via module build: fix.diff applied cleanly; radeon.ko built under -Werror with 0 errors; sumo_dpm.o (20056 bytes) and r100.o produced, radeon.ko (2029128 bytes) linked. Runtime before/after not possible (no AMD GPU HW).
baseline (harness): entries[4] clobbered <-- FIRST OOB WRITE; worst case ~512KB past struct patched (module build): OK sumo_dpm.o (20056 bytes); radeon.ko = 2029128 bytes; error count: 0; RADEON_DONE
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- s
- u
- m
- o
- _
- d
- p
- m
- .
- c
- :
- 1
- 6
- 1
- 6
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- s
- u
- m
- o
- _
- d
- p
- m
- .
- c
- :
- 1
- 6
- 2
- 2
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- s
- u
- m
- o
- _
- d
- p
- m
- .
- c
- :
- 1
- 6
- 2
- 4
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- s
- u
- m
- o
- _
- d
- p
- m
- .
- c
- :
- 1
- 6
- 2
- 6
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- s
- u
- m
- o
- _
- d
- p
- m
- .
- h
- :
- 5
- 2
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- s
- u
- m
- o
- _
- d
- p
- m
- .
- h
- :
- 6
- 6
Detail
Exploit chain
Blocked by dead-code-on-guest hard blocker (valid): radeon DPM not in GENERIC and no AMD GPU HW on the guest; kernel path cannot trigger end-to-end. Primitive proven at harness level (entries[4] OOB via usVoltageIndex, up to ~512KB). Realistic runtime impact with radeon APU HW + crafted VBIOS is large heap corruption / panic. Evidence pack: findings/poc/DF-1437/ (harness.c).
Evidence (decisive lines)
VBIOS usVoltageIndex = 7 (u16, no bound check)
SUMO_MAX_NUMBER_VOLTAGES = 4 (sumo_dpm.h:52)
(Worst case usVoltageIndex=0xFFFF -> write at offset 131070 bytes)
entries[3] = {vid_7bit=0x00 vid_2bit=0x00} (in-bounds, last legal)
entries[4] = {vid_7bit=0x00 vid_2bit=0x00} <-- FIRST OOB WRITE
entries[7] = {vid_7bit=0x15 vid_2bit=0x07} <-- OOB (target)
RESULT: heap OOB write CONFIRMED at sumo_dpm.c:1624
RUN_EXIT=0
PoC changes
Authored harness.c, build.sh, run.sh, fix.diff (skip usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES), VERDICT.md, manifest.json.
Verified recommended fix
In sumo_construct_vid_mapping_table (sumo_dpm.c), at the top of the loop body add if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES) continue;. Matches finding proposal. Full diff in findings/poc/DF-1437/fix.diff.
Verdict
REPRODUCED. sumo_construct_vid_mapping_table (sumo_dpm.c:1616-1629) writes vid_mapping_table->entries[table[i].usVoltageIndex] (sumo_dpm.h:66, fixed [SUMO_MAX_NUMBER_VOLTAGES=4]) where usVoltageIndex is a u16 (0..65535) from the VBIOS sAvail_SCLK list with NO bound check. With usVoltageIndex>=4 the writes overflow entries[4]; with 0xFFFF the write lands ~512KB past the struct. Confirmed by harness: entries[4]/[7] clobbered. Also reachable via trinity_dpm.c and kv_dpm.c (3 APU DPM drivers).
No comments yet.