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

Heap OOB writes into smc_state_table.GraphicsLevel[8]/MemoryLevel[4] via unclamped VBIOS SCLK/MCLK DPM counts (incl. unguarded MemoryLevel[count-1] store)

Summary

The populate loops write GraphicsLevel[i] (array of 8) for i < sclk count and MemoryLevel[i] (array of 4) for i < mclk count, plus count-1 stores (the :1133 one unguarded - wraps to 0xFFFFFFFF if a zero count survives a failed setup). Counts are the same unclamped u8-bounded VBIOS values; memset covers only the fixed spans. Counts 9..255 stomp the remaining SMC tables inside struct tonga_smumgr and, past the ~KB struct, escape the kzalloc allocation. VERIFIED: guest demonstrator prints exact extents (16 SCLK entries -> 512B past the array; 9 MCLK -> MemoryLevel[4..8] OOB + watermark at +768). Distinct from DF-1271/1272 (different array sinks).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3909 Β· 11 files
FileTypeDescriptionSize
trigger_analysis.c trigger-source userspace demonstrator of the kernel index/pointer/division arithmetic 3.1 KB view raw
build.sh build-script cc build of the demonstrator 65 B view raw
run.sh run-script runs the demonstrator 89 B view raw
build.log build-log guest compiler output 11 B view raw
run.log run-log guest runtime output (decisive run) 505 B view raw
env.txt environment guest uname + pciconf (no AMD GPU / no MPT HBA) 838 B view raw
fix.diff suggested-fix git-apply-able unified diff 3.7 KB view raw
fix_build.log build-log fix apply + nativekernel rebuild summary, rc=0 -Werror 6.3 KB view raw
VERDICT.md verdict full verification narrative 2.8 KB ↓ raw
README.md readme human-readable summary 2.6 KB ↓ raw
../DF-3908/fix_kernel_full.log build-log full nativekernel build log shared from DF-3908 pack 5.6 MB ↓ download
README.md readme human-readable summary
↓ download raw

DF-3909 β€” Tonga/Fiji SMC state table: heap OOB writes into GraphicsLevel[8] / MemoryLevel[4] via unclamped VBIOS DPM counts

File: sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c Lines: 709-742, 1673-1675 (tonga_populate_all_graphic_levels, clock stretcher read), 1107-1133 (tonga_populate_all_memory_levels) Severity: High (kernel heap corruption) β€” hardware-gated (Tonga/Fiji + crafted VBIOS) Class: memcorrupt / CWE-787, pass 2 (checklist items (a)/(e): the graphic/memory level tables the knowns did not touch)

Build / Run

./build.sh && ./run.sh

Expected output

GraphicsLevel[8] span        : 512 bytes
sclk dep count (VBIOS u8)    : 16
OOB GraphicsLevel writes     : 8, worst write ends at GraphicsLevel+1024
  -> stomps MemoryACPILevel/MemoryLevel[4]/LinkLevel[8]/... (intra-struct)
MemoryLevel[4] span          : 384 bytes; mclk count 9
OOB MemoryLevel writes       : 5 (worst ends at +864); watermark store at +768 (also OOB)
count==0 form                : MemoryLevel[(uint32)(0-1)] = wild write at +4294967295*96
trigger rc=1 (1 == OOB index math demonstrated)

Root cause

Same unclamped dpm_table->sclk_table.count / mclk_table.count driver as DF-3908, but the sinks are the heap arrays inside the kzalloc'd struct tonga_smumgr (tonga_smumgr.h:66): - smc_state_table.GraphicsLevel[SMU72_MAX_LEVELS_GRAPHICS=8] β€” loop at :709-712 writes GraphicsLevel[i] for i < count; :726 watermark store at GraphicsLevel[count-1]; :740/:769 pcieDpmLevel stores; the clock stretcher additionally READS GraphicsLevel[GraphicsDpmLevelCount-1] (:1673-1675). - smc_state_table.MemoryLevel[SMU72_MAX_LEVELS_MEMORY=4] β€” loop at :1107-1114; boot-level watermark store at MemoryLevel[count-1] (:1133) is additionally unguarded against count==0 (wild index 0xFFFFFFFF; only reachable if a setup failure is ignored per DF-3686). GraphicsLevel is followed in-struct by MemoryACPILevel, MemoryLevel[4], LinkLevel[8], ACPILevel, UvdLevel[8], VceLevel[8], AcpLevel[8] … so counts 9..255 corrupt the rest of the uploaded SMC tables and, past ~5 KB, run beyond the allocation entirely. Distinct from knowns: DF-1271 = UvdLevel/VceLevel/AcpLevel via mm_dep count; DF-1272 = Sclk_voltageOffset[8] via vdd_dep_on_sclk count; neither touches the GraphicsLevel/MemoryLevel arrays.

Fix

fix.diff clamps sclk_count/mclk_count to the array bounds at every use (including GraphicsDpmLevelCount/MemoryDpmLevelCount and the count-1 stores). Validated: applied on guest /usr/src, full nativekernel rebuild rc=0, -Werror clean (fix_build.log; full log in ../DF-3908/fix_kernel_full.log:28191).

VERDICT.md verdict full verification narrative
↓ download raw

DF-3909 β€” Verification Verdict

Status: inconclusive (reproduced=0) Impact: none (no Tonga/Fiji hardware on the guest) Confidence: certain (source-level)

Finding

tonga_populate_all_graphic_levels() / tonga_populate_all_memory_levels() write smc_state_table.GraphicsLevel[i] (i < sclk_table.count) and MemoryLevel[i] (i < mclk_table.count) β€” fixed arrays of 8 and 4 entries β€” plus MemoryLevel[count-1] (:1133, unguarded) and GraphicsLevel[GraphicsDpmLevelCount-1] (stretcher read, :1673-1675). Counts are VBIOS-controlled (u8 dep-table entry counts; see DF-3908 chain) and never clamped to the array bounds β†’ heap OOB writes/reads inside (and past, for large counts) the kzalloc'd struct tonga_smumgr.

Source proof chain

  1. Count provenance: process_pptables_v1_0.c get_{sclk,mclk}_voltage_dependency_table (count = ucNumEntries, u8) β†’ smu7_hwmgr.c smu7_setup_dpm_tables_v1 (:752-830, no clamp; dpm_levels[8] overflow en route is DF-1166).
  2. Sinks: tonga_smumgr.c:709-712 (GraphicsLevel[i] populate), :725-727 (count>1 β†’ GraphicsLevel[count-1]), :739-742 and :769-776 (pcieDpmLevel stores for i < count), :1107-1114 (MemoryLevel[i] populate), :1120/:1127-1128 (MemoryLevel[0] fixed stores), :1133 (MemoryLevel[count-1], no count>0 guard), :1673-1675 (GraphicsLevel[GraphicsDpmLevelCount-1] read).
  3. Array dims: smu72_discrete.h:265-267 (GraphicsLevel[8], MemoryLevel[4]); struct order GraphicsLevel β†’ MemoryACPILevel β†’ MemoryLevel[4] β†’ LinkLevel[8] β†’ … determines what gets stomped.
  4. memset at :707/:1105 only covers sizeof(level)Γ—MAX β€” no protection.

Why inconclusive

Same as DF-3908: the path runs only on Tonga/Fiji powerplay init; guest has no AMD GPU. The demonstrator (run.log) shows the OOB write extents for count=16/9 (e.g. worst GraphicsLevel write ends +512 B past the array) and the count==0 wild-index form.

Fix validation

fix.diff introduces sclk_count/mclk_count = MIN(count, array bound) at every indexing site, guards the count-1 stores with count>0. Applied with the other four batch fixes; full nativekernel rebuild rc=0, -Werror clean (fix_build.log; tonga compile at fix_kernel_full.log:28191 in DF-3908 pack). fix_status = fixed (compile-validated).

Not covered by knowns

DF-1271 (UVD/VCE/ACP levels via mm_dep count) and DF-1272 (Sclk_voltageOffset via vdd_dep_on_sclk) are different sinks and drivers; LinkLevel[8] was checked and is NOT reachable (pcie count clamped ≀7 in smu7_setup_pcie_table, smu7_hwmgr.c:556-569).

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): fix.diff applied to clean guest /usr/src with the batch; nativekernel rebuild rc=0, 0 errors; tonga_smumgr.c compiled with -Werror (full log in DF-3908 pack, line 28191). Runtime re-test impossible on this guest (no AMD GPU).

fix_build.log (apply + compile lines + NK_DONE rc=0); run.log/build.log (demonstrator); full build log shared from DF-3908/fix_kernel_full.log.
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT (nativekernel, patched, rc=0, -Werror clean)

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log (OOB write extents for counts 16/9 and the count==0 wild-index form); VERDICT.md source chain with array dims at smu72_discrete.h:265-267; fix_build.log (-Werror compile of patched file)

PoC changes

Pass-2 reviewer authored trigger/analysis + fix from source; harness built and run on the DragonFly guest (build.log/run.log); fix compile-validated via full nativekernel rebuild.

Verified recommended fix

Introduce sclk_count/mclk_count = MIN(count, SMU72_MAX_LEVELS_GRAPHICS/MEMORY) at every indexing site; guard the count-1 stores with count>0.

Verdict

Source-certain heap OOB writes: tonga_populate_all_graphic_levels()/tonga_populate_all_memory_levels() write smc_state_table.GraphicsLevel[i] (array of 8) and MemoryLevel[i] (array of 4) for i < unclamped VBIOS DPM counts, plus an unguarded MemoryLevel[count-1] watermark store (:1133) and a GraphicsLevel[GraphicsDpmLevelCount-1] stretcher read (:1673); counts 9..255 corrupt the remaining SMC tables and run past the kzalloc'd struct tonga_smumgr. Demonstrator shows write extents on the guest; kernel fault not observable without Tonga/Fiji hardware.