Unclamped VBIOS SCLK/MCLK DPM counts overflow polaris10 SMC GraphicsLevel[8]/MemoryLevel[4] and the 384-byte STACK MC-arb timing table entries[8][4]
Summary
iceland/fiji DF-4000/DF-4001 family on SMU74: sclk/mclk counts flow unclamped from VBIOS into populate_all_graphic_levels (GraphicsLevel[8] + GraphicsDpmLevelCount u8 truncation re-feeding update_dpm_settings), populate_all_memory_levels (MemoryLevel[4] incl. [count-1] stores; mclk count 5 suffices) and program_memory_timing_parameters (stack arb_regs entries[8][4]: 26 entry writes past at sclk=12/mclk=6; 15,300B past at 255/255). Guest-demonstrated with the kernel's own headers (224B/48B redzone dirty). Crafted-vBIOS heap+stack smash. Clamp fix (all nine batch fixes compile-validated together via nativekernel).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4036 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| polaris_walks.c | β | 19.5 KB | view raw | |
| build.sh | β | 65 B | view raw | |
| run.sh | β | 89 B | view raw | |
| build.log | β | 0 B | β download | |
| run.log | β | 4.8 KB | view raw | |
| env.txt | β | 533 B | view raw | |
| fix.diff | β | 4.1 KB | view raw | |
| fix_build.log | β | 1.2 KB | view raw | |
| README.md | β | 1.1 KB | β raw | |
| VERDICT.md | β | 3.0 KB | β raw | |
| manifest.json | β | 1.3 KB | view raw | |
| verdict.json | β | 4.5 KB | view raw |
DF-4036 β Unclamped VBIOS SCLK/MCLK DPM counts overflow polaris10 SMC GraphicsLevel[8]/MemoryLevel[4] and the 384-byte STACK MC-arb timing table
File: sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c
Severity: High | Class: CWE-787 Out-of-bounds Write
Status: hardware-gated β source-certain; runtime reproduction impossible on the audit guest
(no Polaris GPU / no AMD53C974 HBA β see env.txt). Verdict: inconclusive, confidence certain.
Build & run (on the DragonFly guest)
./build.sh # compiles the demonstrator (uses the guest's kernel headers) ./run.sh # reproduces the exact index arithmetic / branch selection
Expected: the DF-4036 section of run.log shows the OOB offsets / panic-branch selection / fault.
Full guest details in env.txt.
Fix validation
fix.diff applied (with all DF-4036..DF-4044 patches together) to a clean guest /usr/src copy;
make nativekernel KERNCONF=X86_64_GENERIC completed with 0 errors under -Werror
(see fix_build.log β polaris10_smumgr.o recompiled).
Sources restored to pristine afterwards (md5-verified).
DF-4036 VERDICT β Unclamped VBIOS SCLK/MCLK DPM counts overflow polaris10 SMC GraphicsLevel[8]/MemoryLevel[4] and the 384-byte STACK MC-arb timing table
Bottom line
Source-certain kernel heap + stack OOB writes, iceland/fiji DF-4000/DF-4001 family on SMU74: the SCLK/MCLK dpm counts flow unclamped from the VBIOS PowerPlay dependency tables (process_pptables_v1_0.c ucNumEntries u8<=255 -> smu7_hwmgr.c:783-810 dpm_table.*.count, no clamp) into polaris10_populate_all_graphic_levels (polaris10_smumgr.c:1000-1017, GraphicsLevel[8] writes + GraphicsDpmLevelCount truncation that re-feeds update_dpm_settings:2427), polaris10_populate_all_memory_levels (:1138-1148, MemoryLevel[4] writes incl. the [count-1] DisplayWatermark/EnabledForActivity stores at :1145-1148, MemoryDpmLevelCount truncation) and polaris10_program_memory_timing_parameters (:1365-1380, the 384-byte STACK SMU74_Discrete_MCArbDramTimingTable arb_regs with entries[8][4]: mclk count 5+ corrupts entries[i+1] rows silently and runs off the table at i==7,j>=4 or i>=8; sclk/mclk 255/255 reaches 15300B past). Demonstrated on the guest with the kernel headers: run.log DF-4036a/b/c (224B/48B redzone dirty at counts 12/6; 26 stack-entry writes past the 32-entry table). Hardware-gated: no Polaris GPU on the audit guest -> runtime inconclusive, source certain.
Exploit chain
crafted vBIOS PowerPlay table with sclk/mclk dependency ucNumEntries > 8/4 -> dpm tables -> polaris10 populate walks -> heap OOB writes in struct polaris10_smumgr (kzalloc) + kernel stack smash past the 384B arb_regs local
Why not reproduced on the guest
The audit guest is QEMU/KVM with virtio display only: no AMD GPU, /dev/dri absent (env.txt), so polaris10_powerplay never binds β the crafted-VBIOS trigger cannot be exercised at runtime. The index arithmetic and struct geometry are proven against the kernel headers compiled verbatim (run.log), and the fix is compile-validated (fix_build.log).
Negative results recorded alongside (pass-2 depth)
Checklist item kills: LinkLevel i<=count walk is bounded (pcie count clamped to <=7 at smu7_hwmgr.c:561-569); mc_reg-table walks are not in this file (smu7_smumgr.c owns them); fan-table div0 is known DF-1345; VCE/UVD count overflow is known DF-1346; Smio[32] and SmioTable.Pattern[4] walks are correctly clamped (SMU_MAX_SMIO_LEVELS).
Fix
Clamp every SCLK/MCLK-driven walk to SMU74_MAX_LEVELS_GRAPHICS/MEMORY and SMU__NUM_SCLK_DPM_STATE/SMU__NUM_MCLK_DPM_LEVELS, index dpm_levels modulo MAX_REGULAR_DPM_NUMBER, and store clamped min() into the *DpmLevelCount fields (fix.diff). Applied and compile-validated on the guest (fix_build.log); sys/ tree never modified by the audit.
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): all nine patches applied together to the clean guest /usr/src copy (polaris10_smumgr.c md5 6f39bb32..->19a2b278.., amd.c f577a330..->54ce1518..), make -j4 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with 0 compile errors under -Werror; the patched polaris10_smumgr.o (amdgpu module) and amd.o (GENERIC kernel) both recompiled. Runtime re-test impossible on this guest (device absent). Sources restored to pristine and md5-verified after validation.
findings/poc/DF-4036/fix.diff; findings/poc/DF-4036/fix_build.log (build banner + compile lines + 0 errors)
Confirmed kernel references
- sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c:1000
- sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c:1017
- sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c:1138
- sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c:1145
- sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c:1365
- sys/dev/drm/amd/powerplay/smumgr/polaris10_smumgr.c:1374
- sys/dev/drm/amd/powerplay/inc/smu74_discrete.h:179
- sys/dev/drm/amd/powerplay/inc/smu74_discrete.h:281
- sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:783
Detail
Exploit chain
crafted vBIOS PowerPlay table with sclk/mclk dependency ucNumEntries > 8/4 -> dpm tables -> polaris10 populate walks -> heap OOB writes in struct polaris10_smumgr (kzalloc) + kernel stack smash past the 384B arb_regs local
Evidence (decisive lines)
run.log sections DF-4036a/b/c (redzone scans + stack-frame smash counts); VERDICT.md; fix_build.log; env.txt
PoC changes
Pass-2 reviewer authored demonstrator compiling the kernel's own headers (smu74.h/smu74_discrete.h packed, or a verbatim copy of the driver's amdsentmsg/parsemsg arms) so struct geometry and branch selection are the kernel's; fix.diff generated against the pristine file and compile-validated via full nativekernel rebuild on the guest (shared build with DF-4036..DF-4044, fix_build.log).
Verified recommended fix
Clamp every SCLK/MCLK-driven walk to SMU74_MAX_LEVELS_GRAPHICS/MEMORY and SMU__NUM_SCLK_DPM_STATE/SMU__NUM_MCLK_DPM_LEVELS, index dpm_levels modulo MAX_REGULAR_DPM_NUMBER, and store clamped min() into the *DpmLevelCount fields (fix.diff)
Verdict
Source-certain kernel heap + stack OOB writes, iceland/fiji DF-4000/DF-4001 family on SMU74: the SCLK/MCLK dpm counts flow unclamped from the VBIOS PowerPlay dependency tables (process_pptables_v1_0.c ucNumEntries u8<=255 -> smu7_hwmgr.c:783-810 dpm_table.*.count, no clamp) into polaris10_populate_all_graphic_levels (polaris10_smumgr.c:1000-1017, GraphicsLevel[8] writes + GraphicsDpmLevelCount truncation that re-feeds update_dpm_settings:2427), polaris10_populate_all_memory_levels (:1138-1148, MemoryLevel[4] writes incl. the [count-1] DisplayWatermark/EnabledForActivity stores at :1145-1148, MemoryDpmLevelCount truncation) and polaris10_program_memory_timing_parameters (:1365-1380, the 384-byte STACK SMU74_Discrete_MCArbDramTimingTable arb_regs with entries[8][4]: mclk count 5+ corrupts entries[i+1] rows silently and runs off the table at i==7,j>=4 or i>=8; sclk/mclk 255/255 reaches 15300B past). Demonstrated on the guest with the kernel headers: run.log DF-4036a/b/c (224B/48B redzone dirty at counts 12/6; 26 stack-entry writes past the 32-entry table). Hardware-gated: no Polaris GPU on the audit guest -> runtime inconclusive, source certain.
No comments yet.