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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3939 Β· 6 files
FileTypeDescriptionSize
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, and entries[7][7] at +588..599 β€” ~24 bytes past the stack object, values McArbDramTiming / McArbDramTiming2 (u32 MMIO reads of MC_ARB_DRAM_TIMING{,2} computed by the VBIOS atomctrl_set_engine_dram_timings_rv770 from the attacker's chosen engine/memory clocks) plus McArbBurstTime (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.

VERDICT.md
↓ download raw

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 of entries[8][6] = 8612 = 576 bytes (sys/dev/drm/amd/powerplay/inc/smu7_discrete.h:223-236: entry = u32+u32+u8+pad3 = 12B; dims SMU__NUM_SCLK_DPM_STATE=8 x SMU__NUM_MCLK_DPM_LEVELS=6 from sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.h:26-27).
  • ci_smumgr.c:1658-1663 β€” the loop bounds are data->dpm_table.sclk_table.count and data->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 writes dpm_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-346 via phm_trim_voltage_table_to_fit_state_table + smum_get_mac_definition), and the PCIE table is capped with min(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_testable
baseline no→ patch + rebuild →patched clean

Fix 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
↓ fix.diffper-fix-DF-3939

Confirmed kernel references

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.