Kernel stack OOB write in ci_program_memory_timing_parameters: VBIOS SCLK/MCLK DPM counts index fixed stack table arb_regs.entries[8][6] (DF-3908 twin)
Summary
The function fills a 576-byte STACK object whose entries[] is [8][6] for CI using the raw VBIOS-derived loop bounds. The MCLK family is the only one without an upstream trim (voltages and PCIE are trimmed). mclk count 7-8 gives j=6,7: rows alias wrong cells; with sclk count 8, row i=7 writes up to 24 bytes PAST the stack object with VBIOS-computed timing values. Reached at DPM init and every OD update. Crafted VBIOS on Bonaire/Hawaii: repeatable kernel stack corruption - panic to control-flow hijack on non-hardened kernels. Clamp fix (tonga twin DF-3908).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3939 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.1 KB | β raw | |
| VERDICT.md | β | 4.1 KB | β raw | |
| fix.diff | β | 809 B | view raw | |
| env.txt | β | 1.2 KB | view raw | |
| manifest.json | β | 1.2 KB | view raw | |
| verdict.json | β | 3.6 KB | view raw |
DF-3939 β Kernel stack OOB write in ci_program_memory_timing_parameters (CI/SMU7 ARB timing table)
Finding
sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:1648-1681
static int ci_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
{
...
SMU7_Discrete_MCArbDramTimingTable arb_regs; /* 576-byte STACK object */
...
for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
result = ci_populate_memory_timing_parameters
(hwmgr, ..., &arb_regs.entries[i][j]);
arb_regs.entries is [SMU__NUM_SCLK_DPM_STATE=8][SMU__NUM_MCLK_DPM_LEVELS=6]
(sys/dev/drm/amd/powerplay/inc/smu7_discrete.h:233-236, CI constants from
sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.h:26-27). The loop bounds come
from the VBIOS-parsed DPM table counts (dpm_table->sclk_table.count,
dpm_table->mclk_table.count), which for MCLK can legitimately reach
MAX_REGULAR_DPM_NUMBER = 8 (sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.h:95,
smu7_hwmgr.h:100) β nothing trims them to the SMC table's 6
(smu7_setup_dpm_tables_v0, sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:704-710,
copies the VBIOS ucNumEntries-sized dependency table
(processpptables.c:391) into dpm_levels[8] with no SMU7_MAX_LEVELS_MEMORY clamp).
Trigger
Crafted VBIOS powerplay table on a Bonaire/Hawaii (AMDGPU_FAMILY_CI) GPU with
vdd_dep_on_mclk containing >= 7 distinct MCLK entries (and, to push the
write past the end of the whole stack object, 8 distinct SCLK entries so
the outer loop reaches row i=7):
- mclk count 7-8 β
j β {6,7}: - rows i<7: writes alias into
entries[i+1][0..1]β in-object but wrong cells (corrupt SMC timing data β logic corruption); - row i=7:
entries[7][6]at byte offset 772+612 = 576 = exactly past the 576-byte object, andentries[7][7]at +588..599 β ~24 bytes past the stack object, valuesMcArbDramTiming/McArbDramTiming2(u32 MMIO reads of MC_ARB_DRAM_TIMING{,2} computed by the VBIOSatomctrl_set_engine_dram_timings_rv770from the attacker's chosen engine/memory clocks) plusMcArbBurstTime(u8).
Called at DPM init: ci_init_smc_table β ci_program_memory_timing_parameters
(ci_smumgr.c:2002), and on OD updates ci_update_sclk_threshold β
ci_program_mem_timing_parameters (ci_smumgr.c:2239).
Why inconclusive on this guest
Requires an AMD Sea Islands GPU plus a modified VBIOS. The audit QEMU guest
has no AMD PCI device at all (env.txt: only Intel PIIX4, QEMU virtio-gpu,
virtio-net/blk β no vendor 0x1002), so the path cannot execute. The struct
math is source-certain: this is the CI twin of the verified tonga finding
DF-3908 (tonga_smumgr.c:1492-1507, entries[8][4] vs MCLK counts up to 8).
Reproduce (on hardware)
Flash a CI board VBIOS whose ATOM powerplay vdd_dep_on_mclk table has 7-8
distinct entries (and sclk dep table with 8), boot with amdgpu dpm enabled;
ci_program_memory_timing_parameters scribbles past the 576-byte stack object
during ci_init_smc_table β expect corruption/panic on stack canary kernels,
silent adjacent-stack corruption otherwise.
DF-3939 β VERDICT
Status: inconclusive (hardware-gated) β source-level certainty: HIGH/certain. Impact class: kernel stack out-of-bounds write (CWE-787), crafted-VBIOS vector.
Root cause (path:line)
sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:1653βSMU7_Discrete_MCArbDramTimingTable arb_regs;is a stack object ofentries[8][6]= 8612 = 576 bytes (sys/dev/drm/amd/powerplay/inc/smu7_discrete.h:223-236: entry = u32+u32+u8+pad3 = 12B; dimsSMU__NUM_SCLK_DPM_STATE=8xSMU__NUM_MCLK_DPM_LEVELS=6fromsys/dev/drm/amd/powerplay/smumgr/ci_smumgr.h:26-27).ci_smumgr.c:1658-1663β the loop bounds aredata->dpm_table.sclk_table.countanddata->dpm_table.mclk_table.count, never validated against the array dims.- Provenance of the counts (no clamp anywhere on the MCLK side):
- V0 pptable parser:
sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:391βdep_table->count = table->ucNumEntries(u8, up to 255; entries dynamically allocated,hwmgr.h:120-123). sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:704-710β dedup loop writesdpm_levels[...]up to the dep-table count;dpm_levels[MAX_REGULAR_DPM_NUMBER=8](smu7_hwmgr.h:95,98-101). Counts 7-8 fit the hwmgr arrays but exceed the SMC table's 6.- Contrast: VDDC/VDDCI/MVDD voltage tables are trimmed to their SMC level counts (
smu7_hwmgr.c:324-346viaphm_trim_voltage_table_to_fit_state_table+smum_get_mac_definition), and the PCIE table is capped withmin(SMU7_MAX_LEVELS_LINK, count)plus a reserved boot slot (smu7_hwmgr.c:557-569). SCLK/MCLK level counts are the one family with no trim β for SCLK this is harmless (8 == GraphicsLevel[8]); for MCLK it is 8 > 6 = MemoryLevel/entries dim.
Overflow math
&arb_regs.entries[i][j] at byte offset i*72 + j*12:
| sclk_count | mclk_count | effect |
|---|---|---|
| <=8 | <=6 | in-bounds |
| <=7 | 7-8 | j=6,7 alias entries[i+1][0..1] β in-object wrong-cell corruption |
| 8 | 7 | entries[7][6] = offset 576..587 β 12B past the stack object |
| 8 | 8 | entries[7][6..7] = offsets 576..599 β 24B past the stack object |
Written values: McArbDramTiming, McArbDramTiming2 = MMIO reads of
mmMC_ARB_DRAM_TIMING{,2} whose contents the VBIOS computed from the
attacker-chosen engine/memory clocks (ci_populate_memory_timing_parameters,
ci_smumgr.c:1619-1645); McArbBurstTime = MC_ARB_BURST_TIME.STATE0 field.
Reach: both call sites β DPM init (ci_init_smc_table β ci_smumgr.c:2002)
and OD/profile updates (ci_update_sclk_threshold β ci_smumgr.c:2239).
Why not reproduced
The single-tenant audit guest has no AMD GPU (env.txt β pciconf -l shows
only Intel PIIX4 + virtio devices; zero vendor-0x1002 functions) and no CI
hardware can be attached; the path additionally requires a modified VBIOS.
Classification inconclusive mirrors the tonga twins DF-3908/DF-3909 and the
batch precedent DF-3934/DF-3935. No uid=0 chain is developable without the
device: the primitive (24B semi-controlled write past a 576B stack object,
repeatable on every DPM re-init) would on real hardware be a strong stack
corruption candidate.
Fix validation
fix.diff clamps both loops to the array dims (SMU7_MAX_LEVELS_GRAPHICS /
SMU7_MAX_LEVELS_MEMORY). Not testable on this guest (no CI GPU), so
fix_status: not_testable; the diff is bounds-only and matches the upstream
tonga hardening pattern. The deeper fix (trim MCLK count once, in
smu7_setup_dpm_tables_v0/v1, like the voltage/PCIE tables) belongs to
smu7_hwmgr.c and also fixes DF-3940's sinks at the source.
Also noted (not re-reported / out of this file)
- smu7_hwmgr.c:704-710/783-799: dep-table counts > 8 overflow
dpm_levels[8]in the hwmgr backend itself β separate file, flagged to the orchestrator in the batch JSON negatives.
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
not_testableFix not validated on the guest: the trigger requires an AMD Sea Islands GPU plus a crafted VBIOS; the audit guest has no 0x1002 PCI function at all (env.txt). fix.diff is a pure bounds clamp (SMU7_MAX_LEVELS_GRAPHICS/SMU7_MAX_LEVELS_MEMORY) authored post-verification against ci_smumgr.c:1658-1663.
findings/poc/DF-3939/fix.diff + VERDICT.md
Confirmed kernel references
- sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:1653
- sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:1658
- sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:1663
- sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:2002
- sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.h:27
- sys/dev/drm/amd/powerplay/inc/smu7_discrete.h:233
- sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:704
- sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.h:95
- sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:391
Detail
Exploit chain
craft VBIOS with vdd_dep_on_mclk count>=7 (distinct) + vdd_dep_on_sclk count 8 -> amdgpu DPM enable -> ci_init_smc_table -> ci_program_memory_timing_parameters -> 24B semi-controlled write past 576B stack object (repeatable per DPM table update) -> stack corruption / panic; on non-hardened kernels a stack-pivot candidate
Evidence (decisive lines)
findings/poc/DF-3939/VERDICT.md (offset math table), fix.diff, env.txt (no 0x1002 device)
PoC changes
No seed PoC; hardware-gated (AMD CI GPU + crafted VBIOS required, absent from guest).
Verified recommended fix
Clamp the ARB loops to SMU7_MAX_LEVELS_GRAPHICS/SMU7_MAX_LEVELS_MEMORY (or trim MCLK count once in smu7_setup_dpm_tables_v0/v1).
Verdict
CI twin of DF-3908: ci_program_memory_timing_parameters declares a 576-byte STACK object SMU7_Discrete_MCArbDramTimingTable whose entries[] is [8][6] for CI (ci_smumgr.h:26-27; smu7_discrete.h:233-236, entry=12B) but drives it with the raw VBIOS-derived DPM counts (ci_smumgr.c:1658-1663). MCLK counts up to MAX_REGULAR_DPM_NUMBER=8 flow unclamped from the pptable parser (processpptables.c:391 ucNumEntries -> dynamically-sized table) through smu7_setup_dpm_tables_v0 (smu7_hwmgr.c:704-710, dedup into dpm_levels[8]; unlike the VDDC/VDDCI/MVDD trims at smu7_hwmgr.c:324-346 and the PCIE cap at :557-569, MCLK is never trimmed to the SMC table's 6). mclk count 7-8 => j=6,7: rows i<7 alias entries[i+1][0..1] (wrong-cell corruption); with sclk count 8, row i=7 writes offsets 576..599, i.e. up to 24 bytes PAST the stack object, with McArbDramTiming/McArbDramTiming2 values the VBIOS computes from attacker-chosen clocks (ci_populate_memory_timing_parameters :1619-1645). Reachable at DPM init (ci_init_smc_table :2002) and OD update (:2239). Hardware-gated (no AMD GPU in guest, env.txt) => inconclusive, source-certain, exactly like tonga DF-3908.
No comments yet.