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)
PoC verification
Evidence pack
findings/poc/DF-3909 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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).
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
- 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).
- 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).
- Array dims: smu72_discrete.h:265-267 (GraphicsLevel[8], MemoryLevel[4]); struct order GraphicsLevel β MemoryACPILevel β MemoryLevel[4] β LinkLevel[8] β β¦ determines what gets stomped.
- 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
fixedfixed (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.
Confirmed kernel references
- sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:709
- sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:712
- sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:726
- sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:1107
- sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:1114
- sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:1133
- sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:1673
- sys/dev/drm/amd/powerplay/inc/smu72_discrete.h:265
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.
No comments yet.