DF-3908 / trigger_analysis.c
/* * DF-3908 trigger/analysis — kernel stack OOB write in * tonga_program_memory_timing_parameters() (sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:1492-1507) * * Kernel path (hardware-gated: needs Tonga/Fiji GPU + crafted VBIOS): * smu7_setup_dpm_tables_v1() copies the VBIOS SCLK/MCLK dependency-table * entry counts (u8, up to 255, only deduplicated — never clamped to * SMU72_MAX_LEVELS_*) into data->dpm_table.sclk_table.count / * mclk_table.count. tonga_init_smc_table() then calls * tonga_program_memory_timing_parameters(), which indexes a 384-byte * STACK object * SMU72_Discrete_MCArbDramTimingTable arb_regs; // entries[8][4], 12 B/entry * with * for (i = 0; i < sclk_table.count; i++) * for (j = 0; j < mclk_table.count; j++) * populate(..., &arb_regs.entries[i][j]); * For sclk_count>8 or mclk_count>4 the writes run past the stack object * (up to (255*4+255)*12 = 15300 bytes past a 384-byte frame), smashing * adjacent stack frames / saved return addresses with GPU DRAM-timing * register values derived from VBIOS-controlled clocks. * * This userspace harness reproduces the exact index arithmetic and prints * which writes land out of bounds (byte offset vs. the 384-byte object). */ #include <stdio.h> #include <stdint.h> #define SMU72_MAX_LEVELS_GRAPHICS 8 #define SMU72_MAX_LEVELS_MEMORY 4 #define ENTRY_SZ 12 /* 2 x uint32 + uint8 + pad[3] */ int main(void) { /* crafted VBIOS: 12 distinct SCLK dep entries, 6 distinct MCLK entries */ uint32_t sclk_count = 12, mclk_count = 6; uint32_t obj_bytes = SMU72_MAX_LEVELS_GRAPHICS * SMU72_MAX_LEVELS_MEMORY * ENTRY_SZ; /* 384 */ uint32_t i, j, oob_writes = 0, first_oob = 0, worst = 0; for (i = 0; i < sclk_count; i++) { for (j = 0; j < mclk_count; j++) { uint32_t off = (i * SMU72_MAX_LEVELS_MEMORY + j) * ENTRY_SZ; if (off + ENTRY_SZ > obj_bytes) { if (oob_writes == 0) first_oob = off; if (off > worst) worst = off; oob_writes++; } } } printf("arb_regs stack object : %u bytes (entries[8][4], 12B each)\n", obj_bytes); printf("VBIOS dep counts (sclk,mclk) : %u x %u\n", sclk_count, mclk_count); printf("total writes : %u\n", sclk_count * mclk_count); printf("OOB writes past stack object : %u (first at +%u, worst at +%u..+%u)\n", oob_writes, first_oob, worst, worst + ENTRY_SZ - 1); printf("=> kernel stack corruption up to %u bytes past a %u-byte frame\n", worst + ENTRY_SZ - obj_bytes, obj_bytes); return (oob_writes > 0) ? 1 : 0; /* rc!=0 == corruption demonstrated */ } |