Missing bounds checks on BIOS-supplied array indices in si_parse_power_table (nonClockInfoIndex and VCE clk_idx)
Summary
si_parse_power_table at si_dpm.c:7253-7255: nonClockInfoIndex read from BIOS used unvalidated to index non_clock_info_array->nonClockInfo[] with NO check against ucNumEntries. Clock loop below DOES check (:7269). Same at :7287-7290 VCE clk_idx no bounds check. Plus power_state_offset advanced by ucNumDPMLevels (:7281) no range check. Crafted/malformed VBIOS -> OOB read from BIOS mapping -> info leak via sysfs pp_dpm_sclk or panic. Attacker: VFIO GPU passthrough romfile or corrupt EEPROM. Fix: validate all BIOS indices against ucNumEntries.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1127 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | BIOS mapping replica; demonstrates OOB at nonClockInfoIndex=42 | 3.3 KB | view raw |
| fix.diff | suggested-fix | bounds check on nonClockInfoIndex in BOTH amdgpu and radeon si_dpm.c | 2.0 KB | view raw |
| build.sh | build-script | cc -O2 -o harness harness.c | 95 B | view raw |
| run.sh | run-script | timeout 10 ./harness | 67 B | view raw |
| build.log | build-log | final successful build | 13 B | view raw |
| run.log | run-log | decisive run incl OOB-read marker | 479 B | view raw |
| env.txt | environment | uname, cc version, pciconf (QEMU VGA stub, not AMD GPU) | 403 B | view raw |
| VERDICT.md | verdict | full narrative + finding-path correction (amdgpu dead, radeon live) | 3.7 KB | β raw |
| README.md | readme | finding summary + build/run/expected | 1.8 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-1127 β Missing bounds checks on BIOS-supplied array indices in si_parse_power_table (AMD GPU)
Finding
si_parse_power_table at sys/dev/drm/amd/amdgpu/si_dpm.c:7253-7255:
nonClockInfoIndex is read from BIOS and used unvalidated to index
non_clock_info_array->nonClockInfo[] with no check against ucNumEntries.
The sibling clock loop at :7269 DOES check
if (clock_array_index >= clock_info_array->ucNumEntries) continue; β
proving the omission is an oversight. Same issue for VCE clk_idx at
:7288-7290. Crafted/malformed VBIOS β OOB read from BIOS mapping β
info leak via sysfs pp_dpm_sclk or panic.
IMPORTANT correction to the finding: the cited file
sys/dev/drm/amd/amdgpu/si_dpm.c is NOT compiled (absent from the
amdgpu Makefile SRCS). The same bug exists in the live copy
sys/dev/drm/radeon/si_dpm.c:6848-6850 which IS compiled into
radeon.ko (confirmed via nm /boot/kernel/radeon.ko β si_dpm_init).
The fix.diff patches BOTH copies.
Reachability on this guest
NOT reachable. The VGA device is a QEMU stub (chip=0x11111234, not an
AMD GPU). radeon.ko is loadable but never attaches to this hardware. Latent.
A userspace harness demonstrates the OOB read at a bogus BIOS index.
Build / Run / Expected
cc -O2 -o harness harness.c # build.sh ./harness # run.sh # Expected: "READ PAST MAPPING BOUNDARY -> kernel OOB read" at index 42
Files
harness.cβ simulates a BIOS mapping with a valid 4-entry array and demonstrates OOB atnonClockInfoIndex = 42.fix.diffβ adds the bounds check to BOTHamdgpu/si_dpm.c(as cited) andradeon/si_dpm.c(the compiled copy). Validated:radeon.kobuilds withrc=0.build.log/run.log/env.txtβ captured outputs.
VERDICT β DF-1127
Verdict: REPRODUCED (primitive) / NOT REACHABLE on guest (HW-gated)
The cited bug is real and confirmed by source trace + userspace
demonstration. Important correction: the finding cited
sys/dev/drm/amd/amdgpu/si_dpm.c which is dead code on DragonFly
(absent from the amdgpu Makefile SRCS). The same bug exists in the
compiled copy sys/dev/drm/radeon/si_dpm.c:6848-6850 which IS shipped
in radeon.ko. Both are patched in fix.diff.
Mechanism (confirmed path:line)
si_parse_power_table(amdgpu copysi_dpm.c:7210, radeon copysi_dpm.c:6808) parses the PowerPlayInfo table from VBIOS.- amdgpu
:7253-7255/ radeon:6848-6850:c non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index];nonClockInfoIndexis read from the (untrusted) VBIOS with no check againstucNumEntries. - The sibling clock loop at amdgpu
:7267-7275/ radeon:6864-6872does checkif (clock_array_index >= clock_info_array->ucNumEntries) continue;β proving the omission is an oversight, not policy. - Same issue at amdgpu
:7288-7290/ radeon:6885for VCEclk_idx. - Crafted/malformed VBIOS β
nonClockInfo[huge_index]β OOB read from BIOS mapping β info leak via sysfspp_dpm_sclkor panic.
Reproduction (userspace harness)
The harness builds a simulated BIOS mapping with a valid 4-entry
nonClockInfo array, then indexes at nonClockInfoIndex = 42:
[buggy path] si_dpm.c:7253-7255 -- NO bounds check nonClockInfoIndex = 42 (ucNumEntries = 4) accesses bios_mapping[674] (mapping size = 256) -> READ PAST MAPPING BOUNDARY -> kernel OOB read
Impact ceiling
- Per-trigger: kernel OOB read from BIOS mapping. The read data feeds
si_parse_pplib_non_clock_infowhich populatesdpm.ps[i]β some fields are exposed via sysfs (pp_dpm_sclk) β info leak. A sufficiently out-of-range index may fault β panic. - Privilege: requires AMD GPU (Tahiti/Southern Islands) + crafted VBIOS (VFIO GPU passthrough romfile, corrupt EEPROM). Not local unpriv.
- Realistic: VFIO passthrough with attacker-controlled romfile is the realistic vector. Niche but real in cloud/VFIO scenarios.
Fix
fix.diff adds the bounds check to both copies:
if (non_clock_array_index >= non_clock_info_array->ucNumEntries) {
power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
continue;
}
β mirroring the existing clock-loop check. The power_state_offset advance
is duplicated so the continue correctly skips to the next state.
Validated: radeon.ko builds with RC=0 after applying the fix (this
is the module that actually ships the bug).
Fix validation
- Patch applies cleanly to both files: amdgpu
Hunk #1 succeeded at 7251, radeonHunk #1 succeeded at 6846. makeinsys/dev/drm/radeon/βradeon.kolinked (2.0 MB),rc=0.amdgpu.koalso builds withrc=0(though it doesn't compile si_dpm.c).- Cannot boot-test (no AMD GPU; VGA is a QEMU stub
chip=0x11111234);fix_status: not_testable.
Correction to the finding
The finding cites sys/dev/drm/amd/amdgpu/si_dpm.c β this file is NOT
compiled into any shipped module (not in amdgpu's Makefile SRCS). The live
copy with identical code and the identical bug is
sys/dev/drm/radeon/si_dpm.c, confirmed compiled via
nm /boot/kernel/radeon.ko | grep si_dpm_init. The fix.diff patches
both; the radeon copy is the one that matters for shipped security.
PoC changes
harness.cwritten from scratch. Simulates a BIOS mapping and demonstrates the OOB read at a bogus index, with a side-by-side comparison to the validated clock loop.
Fix verification
not_testablecompile validated
module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source+harness. si_parse_power_table nonClockInfoIndex no bounds check. Finding cited wrong file (amdgpu vs radeon). No AMD GPU.
No comments yet.