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

fiji clock-stretcher walk overflows Sclk_voltageOffset[8] using the raw VBIOS SCLK-dependency count

Summary

DF-1272 sibling: the walk uses the RAW VBIOS count (<=255), not even the dedup'd dpm count - writing Sclk_voltageOffset[8] (the DpmTable tail): counts past ~24 run off smc_state_table into the rest of the fiji_smumgr alloc and past it. The walk executes BEFORE the stretch_amount validation, so a 'rejected' VBIOS still smears first. Clamp fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4004 Β· 8 files
FileTypeDescriptionSize
README.md β€” 1.8 KB ↓ raw
VERDICT.md β€” 1.5 KB ↓ raw
build.sh β€” 65 B view raw
run.sh β€” 89 B view raw
run.log β€” 3.8 KB view raw
env.txt β€” 493 B view raw
fix.diff β€” 7.7 KB view raw
trigger_analysis.c β€” 17.3 KB view raw

DF-4004 β€” fiji clock-stretcher walk overflows Sclk_voltageOffset[8] with the raw VBIOS SCLK-dep count

File: sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1706-1719 (DDT read walk :1792-1810) Class: kernel heap OOB write (memcorrupt) β€” DF-1272 (tonga Sclk_voltageOffset[8]) sibling Severity: Medium Β· Confidence: certain (source) Β· runtime hardware-gated

Build / Run / Expected

Same demonstrator as DF-4001 (./build.sh && ./run.sh, section === DF-4004 ===):

dep_sclk->count=12 (RAW count, not the dedup'd dpm count): writes at [8..11] are OOB
array sits at DpmTable+1576 of 1632B ... count 255 writes 247B past the array, off the end of smc_state_table

Source chain

fiji_populate_clock_stretcher_data_table walks for (i = 0; i < sclk_table->count; i++) where sclk_table = table_info->vdd_dep_on_sclk (the RAW VBIOS dep table, count = ucNumEntries ≀ 255 β€” not even the dedup'd dpm count) and writes smc_state_table.Sclk_voltageOffset[i] (:1718) β€” a fixed uint8_t[8] at DpmTable+1576 (smu73_discrete.h:361) followed only by ClockStretcherDataTable/CKS_LOOKUPTable (struct tail): count > ~24 runs past the whole smc_state_table into the remainder of the fiji_smumgr allocation (ulv_setting/power_tune_table) and beyond. The second walk (:1792) reads GraphicsLevel[j] for j < GraphicsDpmLevelCount (also unclamped, OOB read).

Gating: PHM_PlatformCaps_ClockStretcher is set for PP_TABLE_V1 parts when feature_mask & PP_CLOCK_STRETCH_MASK && usClockStretchAmount != 0 (smu7_hwmgr.c:1664-1668); the walk executes BEFORE the stretch_amount range check at :1731, so even a "rejected" VBIOS amount smears the table first.

Fix

fix.diff (shared): clamp both walks (i < 8 / j < SMU73_MAX_LEVELS_GRAPHICS). Compile-validated via nativekernel rebuild (fix_build.log).

VERDICT.md
↓ download raw

VERDICT β€” DF-4004

Status: inconclusive at runtime (hardware-gated); source-certain.

Demonstrated (run.log, section DF-4004): with raw vdd_dep_on_sclk->count = 12 the walk at fiji_smumgr.c:1706-1719 writes Sclk_voltageOffset[8..11] β€” the array is uint8_t[8] at DpmTable+1576 of 1632 (smu73_discrete.h:361), the struct tail. Count 255 writes 247 B past the array, off the end of smc_state_table into the remainder of the fiji_smumgr allocation and past it. Distinct from DF-4001: this walk uses the RAW dependency-table count (table_info->vdd_dep_on_sclk), not the dedup'd dpm count, so even a VBIOS whose dedup collapses below 8 still overflows. The DDT walk :1792-1795 additionally OOB-reads GraphicsLevel[j].

Gating (PP_TABLE_V1 + feature_mask + usClockStretchAmount != 0, smu7_hwmgr.c:1664-1668) is satisfiable by the crafted vBIOS itself, and the walk precedes the stretch_amount range check at :1731.

DF-1272 (tonga Sclk_voltageOffset[8]) sibling; Medium because of the cap gate and the 1-byte-per-entry write granularity. Hardware-gated (env.txt).

Fix: fix.diff clamps both walks; nativekernel rebuild OK (fix_build.log), reverted.

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): both diffs applied to clean guest /usr/src (fiji_smumgr.c md5 800babd0..->d50bdc81.., i915_gem_execbuffer.c 334c7bd9..->dc882976..), make nativekernel KERNCONF=X86_64_GENERIC completed with error_count=0 under -Werror (fix_build.log); behavior additionally model-verified for DF-4007 (PATCHED run balanced). Runtime re-test impossible on this guest (no AMD/Intel GPU). Patch reverted after validation.

findings/poc/DF-4004/fix.diff; findings/poc/DF-4001/fix_build.log; findings/poc/DF-4007/run.log (PATCHED model run for DF-4007)
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT (nativekernel X86_64_GENERIC, patched, -Werror; see fix_build.log)

Confirmed kernel references

Detail

Exploit chain

crafted vBIOS with ClockStretchAmount!=0 -> populate_clock_stretcher_data_table with dep count>8 -> OOB byte writes off the end of smc_state_table

Evidence (decisive lines)

run.log (DF-4004 section: writes at [8..11] OOB, array at DpmTable+1576 of 1632, 247B past at count 255); VERDICT.md; fix_build.log; env.txt

PoC changes

Pass-2 reviewer authored demonstrator compiling the kernel's own smu73.h/smu73_discrete.h (packed) so sizeof/offsets are the kernel's; fix.diff generated mechanically against the pristine file and compile-validated via full nativekernel rebuild on the guest (shared build with DF-4001..DF-4007).

Verified recommended fix

Clamp the clock-stretcher walks to 8 / SMU73_MAX_LEVELS_GRAPHICS (fix.diff)

Verdict

Source-certain heap OOB write: fiji_populate_clock_stretcher_data_table walks i < table_info->vdd_dep_on_sclk->count (RAW VBIOS count, <=255) writing Sclk_voltageOffset[8] (fiji_smumgr.c:1706-1718) and reads GraphicsLevel[j] for j<GraphicsDpmLevelCount (:1792-1795); array is the DpmTable tail (+1576 of 1632), so counts past ~24 run off smc_state_table into the fiji_smumgr allocation and beyond. Walk precedes the stretch_amount validation (:1731), so a 'rejected' VBIOS still smears first. DF-1272 (tonga) sibling. Hardware-gated: inconclusive at runtime, source-certain.