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

Kernel stack OOB write in tonga_program_memory_timing_parameters: VBIOS-controlled SCLK/MCLK DPM counts index fixed stack table arb_regs.entries[8][4]

Summary

The function declares the 384-byte ARB timing table on the stack (entries[8][4]) and indexes it with i < sclk_table.count, j < mclk_table.count - counts copied straight from the VBIOS dependency tables (u8, never clamped). A crafted VBIOS with >8 distinct SCLK or >4 MCLK levels makes the loops write up to ~15.3KB past a 384-byte kernel stack frame with VBIOS-derived GPU DRAM-timing dwords - return-address smash potential on a kernel built -fno-stack-protector. Reached at DPM enable and on OD updates. VERIFIED: guest demonstrator shows 26 OOB writes up to +216B past the frame for a modest 12x6 table, scaling to ~15KB for u8-max counts. Crafted-VBIOS attacker gets a kernel-stack write primitive with semi-controlled content.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3908 Β· 11 files
FileTypeDescriptionSize
trigger_analysis.c trigger-source userspace demonstrator of the kernel index/pointer/division arithmetic 2.7 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) 319 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 926 B 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 3.0 KB ↓ raw
README.md readme human-readable summary 2.4 KB ↓ raw
fix_kernel_full.log build-log full 33k-line nativekernel build log (all five fixes applied) 5.6 MB ↓ download
README.md readme human-readable summary
↓ download raw

DF-3908 β€” Tonga/Fiji SMC ARB timing table: kernel stack OOB write via unclamped VBIOS DPM counts

File: sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c Lines: 1492-1507 (tonga_program_memory_timing_parameters) Severity: High (kernel stack corruption) β€” hardware-gated (Tonga/Fiji GPU + crafted VBIOS) Class: memcorrupt / CWE-787 (out-of-bounds write), pass 2 (checklist item (a): clock-count-driven stack tables)

Build

./build.sh     # cc -O2 -Wall -o trigger_analysis trigger_analysis.c  (on the DragonFly guest)

Run

./run.sh

Expected output

arb_regs stack object        : 384 bytes (entries[8][4], 12B each)
VBIOS dep counts (sclk,mclk) : 12 x 6
total writes                 : 72
OOB writes past stack object : 26 (first at +384, worst at +588..+599)
=> kernel stack corruption up to 216 bytes past a 384-byte frame
trigger rc=1 (1 == OOB writes demonstrated)

The harness reproduces the exact index arithmetic of the kernel loops; the kernel path itself requires Tonga/Fiji hardware (absent from the QEMU guest β€” see env.txt), hence the PoC verdict is inconclusive (source-certain, hardware-gated), consistent with DF-1271/DF-1272/DF-1280 precedent.

Root cause

data->dpm_table.sclk_table.count / mclk_table.count are filled by smu7_setup_dpm_tables_v1() (smu7_hwmgr.c:752-830) directly from the VBIOS SCLK/MCLK dependency-table entry counts (u8, ≀255, deduplicated only β€” the dpm_levels[8] overflow there is DF-1166). No code path clamps them to the SMU72 table sizes before tonga_program_memory_timing_parameters() indexes the stack object SMU72_Discrete_MCArbDramTimingTable arb_regs (entries[SMU__NUM_SCLK_DPM_STATE=8][SMU__NUM_MCLK_DPM_LEVELS=4], 12 bytes/entry = 384 bytes) with for (i...) for (j...) populate(..., &arb_regs.entries[i][j]). With a crafted VBIOS reporting >8 SCLK or >4 MCLK distinct levels, writes run up to ~15 KB past the stack frame with GPU DRAM-timing values derived from VBIOS-controlled clocks (return-address smash potential on machines without stack protector β€” the kernel is built -fno-stack-protector).

Fix

fix.diff clamps both loop bounds with MIN(count, SMU72_MAX_LEVELS_*). Validated: applied to the guest's clean /usr/src, full make nativekernel KERNCONF=X86_64_GENERIC rebuild β†’ rc=0, -Werror clean (fix_build.log, fix_kernel_full.log line 28191 compiles tonga_smumgr.c).

VERDICT.md verdict full verification narrative
↓ download raw

DF-3908 β€” Verification Verdict

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

Finding

VBIOS-controlled SCLK/MCLK DPM counts (bounded only by the u8 dependency-table entry count) index the fixed entries[8][4] stack table SMU72_Discrete_MCArbDramTimingTable arb_regs in tonga_program_memory_timing_parameters() without any clamp β†’ kernel stack OOB write at driver init / OD reprogram time.

Source proof chain

  1. process_pptables_v1_0.c get_sclk_voltage_dependency_table / get_mclk_voltage_dependency_table allocate the dep tables with count = ucNumEntries (u8 ≀ 255) β€” count is VBIOS-controlled.
  2. smu7_hwmgr.c:752-830 smu7_setup_dpm_tables_v1() copies every distinct clock into dpm_table->sclk_table / mclk_table, incrementing count per accepted entry β€” never clamped to SMU72_MAX_LEVELS_* (the dpm_levels[8] overflow on the way is already filed as DF-1166).
  3. smu7_hwmgr.c:3780-3817 smu7_trim_* only flips enabled, never reduces count.
  4. tonga_smumgr.c:2296 calls tonga_program_memory_timing_parameters() from tonga_init_smc_table() (and from the OD path at :2552-2561).
  5. tonga_smumgr.c:1492 declares arb_regs (384-byte stack object); :1497-1502 indexes arb_regs.entries[i][j] for i < sclk_table.count, j < mclk_table.count β€” OOB for iβ‰₯8 / jβ‰₯4. Max extent: (2554+255)12 β‰ˆ 15.3 KB past a 384-byte frame.
  6. Array dims: smu72_discrete.h:156-169 (entries[SMU__NUM_SCLK_DPM_STATE=8][SMU__NUM_MCLK_DPM_LEVELS=4], entry = 2Γ—uint32 + uint8 + pad = 12 B).

Why inconclusive, not reproduced

The path executes only during AMD GPU powerplay init on Tonga/Fiji (chip family AMDGPU_FAMILY_VI, tonga/fiji ASICs). The QEMU guest has no AMD GPU (env.txt: pciconf shows only Intel/QEMU virtual PCI devices). The userspace demonstrator (run.log) reproduces the exact index arithmetic and shows 26 OOB writes for a modest 12Γ—6 crafted VBIOS, but cannot fault a kernel stack that never runs.

Fix validation

fix.diff clamps both loops with MIN(count, SMU72_MAX_LEVELS_*). Applied on the guest's clean /usr/src together with DF-3909/3910/3911/3912; full make -j4 nativekernel KERNCONF=X86_64_GENERIC: tonga_smumgr.c compiled with -Werror (fix_kernel_full.log:28191), error count 0, "Kernel build for X86_64_GENERIC completed", rc=0 (fix_build.log). fix_status = fixed (compile-validated; runtime validation requires hardware).

Prior art

Checklist item (a) β€” the smu7_hwmgr.c twin (amd_pp_clocks.clock[16] stack copies) is DF-3684; this is the tonga_smumgr.c stack-table sink, not covered by DF-1271..DF-1275.

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; make -j4 nativekernel KERNCONF=X86_64_GENERIC completed rc=0 with 0 errors; tonga_smumgr.c compiled with -Werror (fix_kernel_full.log:28191). Runtime re-test impossible on this guest (no AMD GPU).

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

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log (26 OOB writes past the 384-byte object printed on guest); VERDICT.md source chain; fix_build.log + fix_kernel_full.log:28191 (-Werror compile of patched tonga_smumgr.c); env.txt (no AMD GPU)

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

Clamp both loops with MIN(count, SMU72_MAX_LEVELS_GRAPHICS/MEMORY) in tonga_program_memory_timing_parameters().

Verdict

Source-certain kernel stack OOB write: tonga_program_memory_timing_parameters() indexes the 384-byte stack table arb_regs.entries[8][4] with VBIOS-controlled sclk/mclk DPM counts (u8 dep-table entries, never clamped); crafted VBIOS with >8 SCLK or >4 MCLK levels smashes up to ~15KB past the stack frame at DPM init/OD time. Guest demonstrator reproduces the exact index math (26 OOB writes for a 12x6 table); kernel path requires Tonga/Fiji hardware absent from the guest, so the in-kernel fault could not be observed - hardware-gated, matching DF-1271/1272/1280 precedent.