fiji_populate_cac_table overflows BapmVddcVid{Lo,Hi}Sidd[16] and OOB-reads vddc_voltage_table.entries[32]
Summary
The CAC walk loops over vddc_lookup_table->count (VBIOS ucNumEntries <=255; the 16-record alloc is DF-1574's finding) writing BapmVddcVidLoSidd/HiSidd[16] (up to 239B past each) and reading vddc_voltage_table.entries[32] (up to 223 entries past, inside struct smu7_hwmgr). Runs whenever voltage_control != NONE (SVI2 default). Clamp fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4003 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.7 KB | β raw | |
| VERDICT.md | β | 1.3 KB | β raw | |
| build.sh | β | 65 B | view raw | |
| run.sh | β | 89 B | view raw | |
| run.log | β | 3.8 KB | view raw | |
| env.txt | β | 493 B | view raw | |
| fix.diff | β | 7.7 KB | view raw | |
| trigger_analysis.c | β | 17.3 KB | view raw |
DF-4003 β fiji_populate_cac_table overflows BapmVddcVid{Lo,Hi}Sidd[16] and reads vddc_voltage_table.entries[32] OOB
File: sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:772-779
Class: kernel heap OOB write + OOB read (memcorrupt/kernleak)
Severity: Medium Β· Confidence: certain (source) Β· runtime hardware-gated
Build / Run / Expected
Same demonstrator as DF-4001 (./build.sh && ./run.sh, section === DF-4003 ===):
vddc_lookup_count=40: 24 OOB writes past BapmVddcVidLoSidd[16] (and same for HiSidd), 8 OOB reads of vddc_voltage_table.entries[32]
Source chain
table_info->vddc_lookup_table->count = VBIOS ucNumEntries verbatim
(process_pptables_v1_0.c:176 β the lookup buffer itself is only allocated for 16
records, DF-1574 pass 1). fiji_populate_cac_table (:756-782) then loops
for (count = 0; count < lookup_table->count; count++) and
- writes table->BapmVddcVidLoSidd[count] and BapmVddcVidHiSidd[count]
(arrays [SMU73_MAX_LEVELS_VDDC=16], smu73_discrete.h:228-230) β 239 B past
each at count 255, clobbering HiSidd2/level-counts/... inside smc_state_table,
and past the DpmTable end for large counts;
- READS data->vddc_voltage_table.entries[count].value (:774) β a fixed
entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES=32] array inside struct smu7_hwmgr
(ppatomctrl.h:45,207) β 223 entries past at count 255 (OOB read consumed by
phm_get_voltage_index, i.e. smu_helper.c:385-403).
Gated on voltage_control != SMU7_VOLTAGE_CONTROL_NONE (fiji_init_smc_table:1936-1937)
β the normal case on SVI2 boards.
Fix
fix.diff (shared): clamp the walk to SMU73_MAX_LEVELS_VDDC and modulo the
entries[32] read. Compile-validated via nativekernel rebuild (fix_build.log).
VERDICT β DF-4003
Status: inconclusive at runtime (hardware-gated); source-certain.
Demonstrated (run.log, section DF-4003): with vddc_lookup_table->count = 40
(VBIOS ucNumEntries; the 16-record alloc itself is DF-1574's pass-1 finding), the
loop at fiji_smumgr.c:772-779 writes 24 bytes past BapmVddcVidLoSidd[16] and
the same past BapmVddcVidHiSidd[16] (arrays at smu73_discrete.h:228-230,
SMU73_MAX_LEVELS_VDDC=16), and performs 8 OOB reads of the fixed
vddc_voltage_table.entries[32] (:774, ppatomctrl.h:45). At count 255: 239 B
past each array (clobbering the level-count fields / GraphicsLevel region of
smc_state_table) and 223 reads past entries[32] inside struct smu7_hwmgr.
Reached from fiji_init_smc_table:1936-1937 whenever voltage_control != NONE
(the SVI2 default). Hardware-gated like the other fiji findings (env.txt).
Fix: fix.diff clamps the walk to SMU73_MAX_LEVELS_VDDC and bounds the
entries[] read; nativekernel rebuild OK (fix_build.log), reverted.
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
fixedfixed (compile-validated): both diffs applied to clean guest /usr/src (fiji_smumgr.c md5 800babd0..->d50bdc81.., i915_gem_execbuffer.c 334c7bd9..->dc882976..), make nativekernel KERNCONF=X86_64_GENERIC completed with error_count=0 under -Werror (fix_build.log); behavior additionally model-verified for DF-4007 (PATCHED run balanced). Runtime re-test impossible on this guest (no AMD/Intel GPU). Patch reverted after validation.
findings/poc/DF-4003/fix.diff; findings/poc/DF-4001/fix_build.log; findings/poc/DF-4007/run.log (PATCHED model run for DF-4007)
Confirmed kernel references
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:772
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:774
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:775
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1936
- sys/dev/drm/amd/powerplay/inc/smu73_discrete.h:228
- sys/dev/drm/amd/powerplay/inc/smu73.h:101
- sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.h:45
- sys/dev/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c:176
Detail
Exploit chain
crafted vBIOS -> attach/resume -> populate_cac_table with lookup count>16 -> OOB VID writes inside smc_state_table + OOB reads of struct smu7_hwmgr
Evidence (decisive lines)
run.log (DF-4003 section: 24 OOB writes past each BapmVddcVid* Sidd[16], 8 OOB reads of entries[32] at count 40); VERDICT.md; fix_build.log; env.txt
PoC changes
Pass-2 reviewer authored demonstrator compiling the kernel's own smu73.h/smu73_discrete.h (packed) so sizeof/offsets are the kernel's; fix.diff generated mechanically against the pristine file and compile-validated via full nativekernel rebuild on the guest (shared build with DF-4001..DF-4007).
Verified recommended fix
Clamp the cac walk to SMU73_MAX_LEVELS_VDDC and bound the vddc_voltage_table.entries[] read to PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES (fix.diff)
Verdict
Source-certain OOB write+read in fiji_populate_cac_table (fiji_smumgr.c:772-779): vddc_lookup_table->count (VBIOS ucNumEntries<=255, buffer itself only 16 records per DF-1574) indexes BapmVddcVidLoSidd/HiSidd[SMU73_MAX_LEVELS_VDDC=16] (writes, up to 239B past each) and vddc_voltage_table.entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES=32] (reads, up to 223 entries past, inside struct smu7_hwmgr). Demonstrator: 24 OOB writes + 8 OOB reads at count 40. Runs whenever voltage_control != NONE (SVI2 default). Hardware-gated: inconclusive at runtime, source-certain.
No comments yet.