Unclamped VBIOS SCLK/MCLK DPM counts overflow fiji SMC GraphicsLevel[8]/MemoryLevel[4] and the 384-byte STACK MC-arb timing table
Summary
DF-4000 (iceland) family on fiji: the SMC-table populate walks index GraphicsLevel[8], MemoryLevel[4] and the STACK SMU73_Discrete_MCArbDramTimingTable (entries[8][4], 384B) with the raw VBIOS dependency counts (u8<=255). Guest demonstrator compiles the kernel's own packed headers: sclk=12 -> 176B past GraphicsLevel; mclk=6 -> 48B past MemoryLevel (count 5 suffices); arb walk 12x6 -> deepest write 600B into the 384B stack object (216B into the caller frame; 255/255 -> 15,300B past; kernel built -fno-stack-protector). Crafted-vBIOS attach/resume heap+stack smash. Clamp fix compile-validated.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4001 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.3 KB | β raw | |
| VERDICT.md | β | 3.8 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-4001 β Unclamped VBIOS SCLK/MCLK DPM counts overflow fiji SMC state tables incl. a 384-byte STACK MC-arb table
File: sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c
Class: kernel heap + stack OOB write (memcorrupt) β DF-4000 (iceland) / DF-3908/3939/3940 family, fiji variant
Severity: High Β· Confidence: certain (source) Β· runtime hardware-gated
Build / Run / Expected (on the DragonFly audit guest)
./build.sh # cc -O2 -Wall -I /usr/src/sys/dev/drm/amd/powerplay/inc -o fiji_walks trigger_analysis.c ./run.sh # ./fiji_walks
Expected (see run.log): the demonstrator compiles the kernel's own packed
headers (smu73.h, smu73_discrete.h) so sizeof/offsets are the kernel's,
then reproduces the walks with attacker-chosen VBIOS counts (sclk=12, mclk=6):
DF-4001a ... sclk_count=12: 4 OOB level writes, 176 bytes past GraphicsLevel[8]
DF-4001b ... mclk_count=6 (Fiji SMU73 bound is 4!): 2 OOB writes, 48 bytes past MemoryLevel[4]
DF-4001c ... sclk=12 mclk=6: 26 PAST the 32-entry table (max linear entry 49 of 32)
deepest write offset 600B into a 384B stack object -> 216 bytes into the caller frame
Why it is real (source chain, attacker = crafted vBIOS / eGPU flash)
- VBIOS PowerPlay table (v1)
ucNumEntries(u8 β€ 255) is stored verbatim as the dependency-table count:process_pptables_v1_0.c:389(mclk),:436(sclk). - Fiji is pinned to this parser:
hwmgr.c:86(PP_TABLE_V1 default) +hwmgr.c:127(CHIP_FIJI β fiji_smu_funcs; only CI/TOPAZ drop to PP_TABLE_V0). smu7_hwmgr.c:783-810dedups the dep tables intodpm_table.sclk_table.count/mclk_table.countβ unclamped against the fixeddpm_levels[8](DF-1166, pass 1).fiji_populate_all_graphic_levels(fiji_smumgr.c:1026-1036) walkscountentries intolevels[i]=smc_state_table.GraphicsLevel[SMU73_MAX_LEVELS_GRAPHICS=8](smu73_discrete.h:249);[count-1]store at:1042;pcieDpmLevelloops:1055-1057,:1080-1081.struct fiji_smumgris a singlekzalloc(fiji_smumgr.c:339) β heap OOB write past the object for count > ~45 (GraphicsLevel sits at DpmTable+236 of 1632B).fiji_populate_all_memory_levels(:1238-1247,[0]fixups:1250/:1257,[count-1]:1265) intoMemoryLevel[SMU73_MAX_LEVELS_MEMORY=4](smu73_discrete.h:251) β count 5 already overflows.fiji_program_memory_timing_parameters(:1533) declaresSMU73_Discrete_MCArbDramTimingTable arb_regs;on the stack (384 B,entries[8][4],smu73_discrete.h:154-157) and the nested loops:1537-1546writeentries[i][j]for i<sclk_count, j<mclk_count β with 255/255 the walk runs to 15,300 B past a 384-byte kernel-stack object (return-address direction; write content is VBIOS-derived register values).- The clock-stretcher DDT walk additionally READS
GraphicsLevel[j]for j<GraphicsDpmLevelCount (:1792-1795) β OOB read of the same count.
Sinks are reached from fiji_init_smc_table (:1964, :1988) during
pp_hwmgr init (device attach / resume) β privileged-time execution of
attacker-controlled VBIOS bytes (malicious vBIOS flash or hostile eGPU).
Fix
fix.diff clamps every walk to the SMU73 array bounds (and clamps the level
counts handed to the SMC); compile-validated by full nativekernel rebuild
(see fix_build.log).
VERDICT β DF-4001
Status: inconclusive at runtime (hardware-gated); source-certain.
Reproduced
The index arithmetic and corruption extents are reproduced on the audit guest
by trigger_analysis.c (run.log), using the kernel's own packed headers:
| walk | sink (kernel object) | bound | demo counts | OOB observed |
|---|---|---|---|---|
fiji_populate_all_graphic_levels:1026 |
GraphicsLevel[8] (heap, fiji_smumgr kzalloc @ fiji_smumgr.c:339) |
8 | sclk=12 | 4 level writes / 176 B past; [count-1] store at :1042 also OOB |
fiji_populate_all_memory_levels:1238 |
MemoryLevel[4] (heap) |
4 | mclk=6 | 2 writes / 48 B past (mclk count 5 suffices) |
fiji_program_memory_timing_parameters:1537-1546 |
SMU73_Discrete_MCArbDramTimingTable STACK object (:1533) |
entries[8][4] | 12Γ6 | 26 entry writes past, max linear entry 49 of 32, 216 B into caller frame; 255/255 β 15,300 B past |
Struct geometry measured with the kernel's own headers:
sizeof(DpmTable)=1632, GraphicsLevel@+236 (44 B/level), MemoryLevel@+612
(24 B/level), arb entry 12 B, arb table 384 B.
The in-kernel fault could not be observed: the audit guest has no AMD GPU (env.txt: amd-gpu=0, virtio-only), and the trigger requires a Fiji (Fiji XT / R9 Fury) card with a crafted vBIOS β physical attacker / malicious vBIOS / hostile eGPU, same gate as DF-4000 (iceland), DF-3908/3939/3940.
Why the counts are attacker-controlled and unclamped (three-hop provenance)
process_pptables_v1_0.c:425-436get_sclk_voltage_dependency_tableand:378-391get_mclk_voltage_dependency_tablesettable->count = ucNumEntries(VBIOS byte, β€ 255); the allocation matches the count, so no clamp exists anywhere.hwmgr.c:86setspp_table_version = PP_TABLE_V1by default;hwmgr.c:127-130pins CHIP_FIJI tofiji_smu_funcs(only CI/TOPAZ downgrade to PP_TABLE_V0).smu7_hwmgr.c:783-810(smu7_setup_dpm_tables_v1) copies the dep-table entries (dedup by clk) intodpm_table.sclk_table/mclk_table.countβ unclamped vsMAX_REGULAR_DPM_NUMBER(8); the en-routedpm_levels[8]smash is DF-1166 (pass 1, smu7_hwmgr.c). The fiji-side sinks below are this file's:GraphicsLevel[8],MemoryLevel[4], stackentries[8][4], plus the:1792-1795DDTGraphicsLevel[j]OOB read.
No intervening clamp exists: grep the whole populate path β the only min()
on pcie is smu7_hwmgr.c:561 (which is why LinkLevel is safe; see negative
notes in the audit result).
Exploitability (why High)
- Heap: count 12 already writes 176 B past GraphicsLevel[8] inside the
struct fiji_smumgrallocation, corrupting MemoryACPILevel/MemoryLevel/ LinkLevel/Uvd/Vce/Acp/Samu/Ulv/Smio...; count β₯ ~45 runs past the whole kzalloc into adjacent heap (count 255 β 10.8 KB). Content is VBIOS-influenced (clocks/voltages per level). - Stack: the arb walk is a linear stack smash up to 15.3 KB past a 384-byte frame object in the return-address direction; DragonFly kernels are built without stack protectors by default. Trigger context = driver attach/resume (privileged), so this is malicious-vBIOS-class, not unprivileged-local.
Fix validation
fix.diff clamps all walks/counts to the SMU73 bounds. Applied to pristine
guest /usr/src (md5 800babd0.. β d50bdc81..), full make nativekernel
KERNCONF=X86_64_GENERIC rebuild completed (fix_build.log / fix_kernel_full.log),
then reverted. Runtime re-test impossible on this guest (no AMD GPU).
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): 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-4001/fix.diff; findings/poc/DF-4001/fix_build.log; findings/poc/DF-4007/run.log (PATCHED model run for DF-4007)
Confirmed kernel references
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1026
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1042
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1055
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1238
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1265
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1533
- sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c:1792
- sys/dev/drm/amd/powerplay/inc/smu73.h:93
- sys/dev/drm/amd/powerplay/inc/smu73_discrete.h:249
- sys/dev/drm/amd/powerplay/inc/smu73_discrete.h:251
- sys/dev/drm/amd/powerplay/inc/smu73_discrete.h:154
- sys/dev/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c:436
- sys/dev/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c:389
- sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:783
- sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:86
- sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:127
Detail
Exploit chain
crafted vBIOS (malicious flash / hostile eGPU) -> pp_hwmgr init at attach/resume -> fiji_init_smc_table -> SMC-table populate walks with ucNumEntries>bounds -> OOB writes into the fiji_smumgr heap allocation and the 384B kernel-stack arb table (return-address direction; -fno-stack-protector confirmed in the guest kernel build) -> kernel heap corruption / stack control-flow hijack in privileged context
Evidence (decisive lines)
run.log (DF-4001a/b/c sections: +176B/+48B heap, 26/72 stack entry writes OOB, 216B into caller frame, 255/255 -> 15,300B past the 384B stack object); VERDICT.md three-hop provenance; fix_build.log; env.txt (amd-gpu=0)
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 all fiji SMC-table walks to SMU73_MAX_LEVELS_GRAPHICS/MEMORY (and the arb walk to SMU__NUM_SCLK_DPM_STATE x SMU__NUM_MCLK_DPM_LEVELS) as in fix.diff; structurally, clamp the counts at the parser (DF-1574/DF-1166 family)
Verdict
Source-certain kernel heap+stack OOB writes: the fiji (SMU73) SMC-table populate walks index GraphicsLevel[8], MemoryLevel[4] and the 384-byte STACK MCArbDramTimingTable (entries[8][4]) with the raw VBIOS SCLK/MCLK dependency counts (u8 ucNumEntries<=255, unclamped through process_pptables_v1_0.c -> smu7_setup_dpm_tables_v1 -> dpm_table, fiji pinned to this path at hwmgr.c:86/127). Guest demonstrator with the kernel's own packed headers reproduces the exact index math (sclk=12/mclk=6: 4/12 GraphicsLevel writes +176B past GraphicsLevel[8], 2/6 MemoryLevel writes +48B past MemoryLevel[4] (Fiji bound is 4 - count 5 suffices), 26/72 arb entry writes with the deepest at linear entry 49 of 32, 216B into the caller frame; 255/255 reaches 15,300B past the stack object). The in-kernel fault could not be observed - no AMD GPU in QEMU and the trigger requires a Fiji card with a crafted VBIOS (malicious vBIOS flash / hostile eGPU at attach/resume). Hardware-gated, matching the DF-4000 (iceland) precedent. Fix compile-validated by full nativekernel rebuild under -Werror.
No comments yet.