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

vegam_get_dependency_volt_by_clk reads dep_table->entries[count] one record past the heap allocation in the clock-above-max path

Summary

When the requested clock exceeds every dependency entry, the loop exits with i==count; the tail path uses entries[i-1] correctly but the MVDD predicate at :661 reads entries[i].mvdd - exactly one record past the kzalloc'd count-record table. 2-byte OOB heap read used as a boolean; wrong-MVDD selection at worst; hit on every above-max clock query. One-token entries[i-1] fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4072 Β· 5 files
FileTypeDescriptionSize
verdict.json β€” 2.0 KB view raw
README.md β€” 258 B ↓ raw
VERDICT.md β€” 1.5 KB ↓ raw
fix.diff β€” 299 B view raw
manifest.json β€” 773 B view raw

DF-4072 β€” vegam_get_dependency_volt_by_clk entries[count] one-past-end heap OOB read (pass 2)

File: sys/dev/drm/amd/powerplay/smumgr/vegam_smumgr.c:661 Source-level finding. No executable PoC (hardware-gated); see VERDICT.md for the line-by-line trace.

VERDICT.md
↓ download raw

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

Root cause

  • vegam_get_dependency_volt_by_clk() searches for (i = 0; i < dep_table->count; i++) for the first entry with clk >= clock (vegam_smumgr.c:614-642). When the clock exceeds every entry, the loop exits with i == dep_table->count.
  • The tail path then uses entries[i-1] correctly at :645/:653, but the MVDD predicate at :661 reads dep_table->entries[i].mvdd β€” i == count β‡’ exactly ONE RECORD past the allocation.
  • Allocation: process_pptables_v1_0.c:381-389 (mclk) and :425-470 (sclk) kzalloc exactly sizeof(count field) + count * sizeof(record) β€” entries[count] is genuinely past the heap object.

Impact

2-byte OOB heap read used as a boolean; if it happens to be nonzero the code then programs entries[i-1].mvdd (in-bounds). Worst realistic effect: wrong MVDD selection + an OOB read that can fault at a slab boundary. Hit on every "clock above table max" query (e.g. ACPI level with boot clock above the dependency table's max β€” vegam_populate_smc_acpi_level:1125/1163).

Fix

dep_table->entries[i].mvdd -> dep_table->entries[i - 1].mvdd at :661. Sibling pattern of the fiji/polaris off-by-ones filed in pass 2 (DF-40xx series).

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-4072

Confirmed kernel references

Detail

Evidence (decisive lines)

vegam_smumgr.c:614-642 loop, :645 entries[i-1] (correct), :661 entries[i] with i==count (OOB read)

PoC changes

n/a (source-level)

Verified recommended fix

Use dep_table->entries[i - 1].mvdd at line 661.

Verdict

Source-level certain, hardware-gated. In vegam_get_dependency_volt_by_clk(), when the requested clock exceeds every table entry the for-loop exits with i == dep_table->count, and line 661 reads dep_table->entries[i].mvdd -- exactly one record past the kzalloc'd 'count'-record table (process_pptables_v1_0.c allocates sizeof + count*sizeof(record) exactly). One-record heap OOB read (2-byte mvdd field) whose value is only used as a boolean; the value actually programmed comes from entries[i-1]. Sibling of the polaris/fiji off-by-ones; hit on every above-max clock query (ACPI level with boot sclk above table max, etc.).