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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4003 Β· 8 files
FileTypeDescriptionSize
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.md
↓ download raw

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

fixed
baseline no→ patch + rebuild →patched clean

fixed (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)
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT (nativekernel X86_64_GENERIC, patched, -Werror; see fix_build.log)

Confirmed kernel references

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.