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

MVDD stash-table wrong-index reads: entries[count] instead of entries[level] (uninitialized voltage to SMU) and cross-table mvdd_voltage_table.entries[vdd_dep_on_mclk index] (true OOB read)

Summary

Two sites: (1) populate_smc_mvdd_table reads entries[count] inside the loop over 'level' - in-bounds but reads an uninitialized slot and programs the SAME garbage MVDD into every SmioTable2 pattern. (2) populate_mvdd_value indexes mvdd_voltage_table.entries[i] with i from a DIFFERENT table (vdd_dep_on_mclk, count<=255) while capacity is 32 - for i>=32 a real heap OOB read inside struct smu7_hwmgr whose value is programmed as a voltage. Wrong-index + bound fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4073 Β· 5 files
FileTypeDescriptionSize
verdict.json β€” 2.2 KB view raw
README.md β€” 251 B ↓ raw
VERDICT.md β€” 1.7 KB ↓ raw
fix.diff β€” 657 B view raw
manifest.json β€” 777 B view raw

DF-4073 β€” vegam MVDD stash-table wrong-index reads (pass 2, checklist class g)

Sites: vegam_smumgr.c:458-465 (populate_smc_mvdd_table) and :1093-1097 (populate_mvdd_value) Source-level finding. No executable PoC (hardware-gated); see VERDICT.md.

VERDICT.md
↓ download raw

DF-4073 VERDICT β€” source-level certain, hardware-gated

Site 1 β€” wrong loop index (uninitialized slot read)

vegam_populate_smc_mvdd_table() (:458-466) reads data->mvdd_voltage_table.entries[count].value inside for (level = 0; level < count; level++) β€” the index must be level, not count. In-bounds (entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES=32], count clamped to SMU_MAX_SMIO_LEVELS=4 β€” ppatomctrl.h:45,211; smu75.h:53) but it reads an UNINITIALIZED slot and programs the SAME garbage voltage into every SmioTable2.Pattern[level].Voltage β‡’ MVDD DPM misprogramming (hardware behavior).

Site 2 β€” cross-table index (true heap OOB read)

vegam_populate_mvdd_value() (:1093-1097) walks table_info->vdd_dep_on_mclk (count up to 255, VBIOS u8) and on the first matching entry reads data->mvdd_voltage_table.entries[i].value β€” indexing the MVDD table by the MCLK-dependency position. mvdd_voltage_table.entries capacity is 32; for i >= 32 (reachable when dep entries with clk < mclk precede the match β€” a reordered/crafted table) this reads up to ~2.5 KB past entries[] inside the struct smu7_hwmgr heap object, and the value is programmed as a voltage (vegam_populate_smc_acpi_level:1177-1186).

Fixes

entries[count] -> entries[level] at :460; at :1095 validate/bound i against mvdd_voltage_table.count before use.

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

not_testable
baseline no→ patch + rebuild →patched clean

Hardware-gated finding (no AMD VegaM GPU / no LSI mps controller on the audit guest): fix authored at source level (fix.diff) but not build/boot-validated.

fix.diff in this pack; authored post-analysis, not hardware-validated.
↓ fix.diffper-fix-DF-4073

Confirmed kernel references

Detail

Evidence (decisive lines)

vegam_smumgr.c:458-465 (entries[count] vs loop index 'level'); :1093-1097 (mvdd_voltage_table.entries[i] indexed by vdd_dep_on_mclk position); ppatomctrl.h:45,211 (entries[32])

PoC changes

n/a (source-level)

Verified recommended fix

entries[count] -> entries[level] at :460; at :1095 bound/validate i against mvdd_voltage_table.count (or index by mvdd table lookup).

Verdict

Two wrong-index MVDD stash reads (checklist class g). (1) vegam_populate_smc_mvdd_table():459-460 reads data->mvdd_voltage_table.entries[count] inside a loop over 'level' -- should be entries[level]. In-bounds (entries[32], count clamped to SMU_MAX_SMIO_LEVELS=4) but it reads an uninitialized slot and programs the SAME garbage MVDD voltage into every SmioTable2.Pattern[level]. (2) vegam_populate_mvdd_value():1095 indexes data->mvdd_voltage_table.entries[i] with i from a DIFFERENT table (vdd_dep_on_mclk, count up to 255) while the mvdd table's entries capacity is 32 => for i >= 32 a true heap OOB read inside struct smu7_hwmgr, value programmed as a voltage. Hardware-gated (crafted VBIOS).