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

polaris10 MVDD stash walks: SmioTable2.Pattern reads entries[count] instead of entries[level]; populate_mvdd_value walks the raw MCLK-dependency count past mvdd_voltage_table.entries[32]

Summary

Polaris-unique: (a) populate_smc_mvdd_table writes Pattern[level] but reads entries[count] with count=min(count,4) - one past the valid trimmed entries, so all MVDD smio patterns get the stale/zero slot (demonstrated: all 0 instead of 1100..1400); (b) populate_mvdd_value loops i < raw vdd_dep_on_mclk->count reading entries[i] from fixed entries[32] - dep counts 33..255 read past pp_atomctrl_voltage_table into struct smu7_hwmgr. Wrong-index + bound fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4041 Β· 12 files
FileTypeDescriptionSize
polaris_walks.c β€” 19.5 KB view raw
build.sh β€” 65 B view raw
run.sh β€” 89 B view raw
build.log β€” 0 B ↓ download
run.log β€” 4.8 KB view raw
env.txt β€” 533 B view raw
fix.diff β€” 1.0 KB view raw
fix_build.log β€” 1.2 KB view raw
README.md β€” 1.2 KB ↓ raw
VERDICT.md β€” 2.7 KB ↓ raw
manifest.json β€” 1.1 KB view raw
verdict.json β€” 3.9 KB view raw

DF-4041 β€” polaris10 MVDD stash walks: SmioTable2.Pattern reads entries[count] instead of entries[level]; populate_mvdd_value walks the raw MCLK-dependency count past mvdd_voltage_table.entries[32]

File: sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c Severity: Low | Class: CWE-125 Out-of-bounds Read (and wrong-index read) Status: hardware-gated β€” source-certain; runtime reproduction impossible on the audit guest (no Polaris GPU / no AMD53C974 HBA β€” see env.txt). Verdict: inconclusive, confidence certain.

Build & run (on the DragonFly guest)

./build.sh     # compiles the demonstrator (uses the guest's kernel headers)
./run.sh       # reproduces the exact index arithmetic / branch selection

Expected: the DF-4041 section of run.log shows the OOB offsets / panic-branch selection / fault. Full guest details in env.txt.

Fix validation

fix.diff applied (with all DF-4036..DF-4044 patches together) to a clean guest /usr/src copy; make nativekernel KERNCONF=X86_64_GENERIC completed with 0 errors under -Werror (see fix_build.log β€” polaris10_smumgr.o recompiled). Sources restored to pristine afterwards (md5-verified).

VERDICT.md
↓ download raw

DF-4041 VERDICT β€” polaris10 MVDD stash walks: SmioTable2.Pattern reads entries[count] instead of entries[level]; populate_mvdd_value walks the raw MCLK-dependency count past mvdd_voltage_table.entries[32]

Bottom line

Source-certain MCLK-stash defects (polaris-unique checklist item h): (a) polaris10_populate_smc_mvdd_table writes Pattern[level] but reads data->mvdd_voltage_table.entries[count] with count = min(table count, SMU_MAX_SMIO_LEVELS=4) (polaris10_smumgr.c:657) β€” a wrong-index read one past the VALID (trimmed-to-4, smu7_hwmgr.c:344-349) entries, so every MVDD smio pattern is programmed with the stale/zero slot (demonstrated: run.log DF-4041a β€” all patterns 0 instead of 1100..1400); (b) polaris10_populate_mvdd_value loops i < vdd_dep_on_mclk->count (RAW VBIOS u8, :1183) reading mvdd_voltage_table.entries[i] from the fixed entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES=32] array (:1185) β€” dep counts 33..255 read past the pp_atomctrl_voltage_table into the rest of struct smu7_hwmgr (intra-struct heap OOB read; loop only stops early if a clk happens to match). Demonstrated: run.log DF-4041b (8 reads past at count 40). Hardware-gated -> runtime inconclusive, source certain.

Exploit chain

crafted vBIOS: (a) any GPIO-MVDD board config -> all MVDD patterns read the zero slot (mis-programmed memory voltage); (b) vdd_dep_on_mclk->count > 32 -> entries[i] intra-struct OOB reads

Why not reproduced on the guest

The audit guest is QEMU/KVM with virtio display only: no AMD GPU, /dev/dri absent (env.txt), so polaris10_powerplay never binds β€” the crafted-VBIOS trigger cannot be exercised at runtime. The index arithmetic and struct geometry are proven against the kernel headers compiled verbatim (run.log), and the fix is compile-validated (fix_build.log).

Negative results recorded alongside (pass-2 depth)

Checklist item kills: LinkLevel i<=count walk is bounded (pcie count clamped to <=7 at smu7_hwmgr.c:561-569); mc_reg-table walks are not in this file (smu7_smumgr.c owns them); fan-table div0 is known DF-1345; VCE/UVD count overflow is known DF-1346; Smio[32] and SmioTable.Pattern[4] walks are correctly clamped (SMU_MAX_SMIO_LEVELS).

Fix

Read entries[level] in the MVDD pattern loop and bound the populate_mvdd_value walk by PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES (fix.diff). Applied and compile-validated on the guest (fix_build.log); sys/ tree never modified by the audit.

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): all nine patches applied together to the clean guest /usr/src copy (polaris10_smumgr.c md5 6f39bb32..->19a2b278.., amd.c f577a330..->54ce1518..), make -j4 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with 0 compile errors under -Werror; the patched polaris10_smumgr.o (amdgpu module) and amd.o (GENERIC kernel) both recompiled. Runtime re-test impossible on this guest (device absent). Sources restored to pristine and md5-verified after validation.

findings/poc/DF-4041/fix.diff; findings/poc/DF-4041/fix_build.log (build banner + compile lines + 0 errors)
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (nativekernel X86_64_GENERIC rebuilt with all DF-4036..DF-4044 patches; 0 errors under -Werror; see fix_build.log)

Confirmed kernel references

Detail

Exploit chain

crafted vBIOS: (a) any GPIO-MVDD board config -> all MVDD patterns read the zero slot (mis-programmed memory voltage); (b) vdd_dep_on_mclk->count > 32 -> entries[i] intra-struct OOB reads

Evidence (decisive lines)

run.log sections DF-4041a/b; VERDICT.md; fix_build.log; env.txt

PoC changes

Pass-2 reviewer authored demonstrator compiling the kernel's own headers (smu74.h/smu74_discrete.h packed, or a verbatim copy of the driver's amdsentmsg/parsemsg arms) so struct geometry and branch selection are the kernel's; fix.diff generated against the pristine file and compile-validated via full nativekernel rebuild on the guest (shared build with DF-4036..DF-4044, fix_build.log).

Verified recommended fix

Read entries[level] in the MVDD pattern loop and bound the populate_mvdd_value walk by PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES (fix.diff)

Verdict

Source-certain MCLK-stash defects (polaris-unique checklist item h): (a) polaris10_populate_smc_mvdd_table writes Pattern[level] but reads data->mvdd_voltage_table.entries[count] with count = min(table count, SMU_MAX_SMIO_LEVELS=4) (polaris10_smumgr.c:657) β€” a wrong-index read one past the VALID (trimmed-to-4, smu7_hwmgr.c:344-349) entries, so every MVDD smio pattern is programmed with the stale/zero slot (demonstrated: run.log DF-4041a β€” all patterns 0 instead of 1100..1400); (b) polaris10_populate_mvdd_value loops i < vdd_dep_on_mclk->count (RAW VBIOS u8, :1183) reading mvdd_voltage_table.entries[i] from the fixed entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES=32] array (:1185) β€” dep counts 33..255 read past the pp_atomctrl_voltage_table into the rest of struct smu7_hwmgr (intra-struct heap OOB read; loop only stops early if a clk happens to match). Demonstrated: run.log DF-4041b (8 reads past at count 40). Hardware-gated -> runtime inconclusive, source certain.