β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1437

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1437 Β· 12 files
FileTypeDescriptionSize
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
VERDICT.md verdict full narrative: mechanism, reachability, harness, fix
↓ download 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

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED 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
↓ fix.diffn/a (module build)

Confirmed kernel references

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).