DF-3909 / trigger_analysis.c
/* * DF-3909 trigger/analysis — heap OOB writes in * tonga_populate_all_graphic_levels() / tonga_populate_all_memory_levels() * (sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:709-742, 1107-1133) * * Kernel path (hardware-gated: Tonga/Fiji + crafted VBIOS): * data->dpm_table.sclk_table.count / mclk_table.count are filled by * smu7_setup_dpm_tables_v1() straight from the VBIOS dependency tables * (u8 entry count, up to 255, deduplicated only). They are never clamped * to the fixed SMC state arrays: * smc_state_table.GraphicsLevel[SMU72_MAX_LEVELS_GRAPHICS = 8] * smc_state_table.MemoryLevel [SMU72_MAX_LEVELS_MEMORY = 4] * tonga_populate_all_graphic_levels() writes GraphicsLevel[i] for * i < sclk_table.count (OOB for i >= 8: stomps MemoryACPILevel, * MemoryLevel[], LinkLevel[], ... and, for large counts, runs past the * kzalloc'd struct tonga_smumgr entirely), and * tonga_populate_all_memory_levels() writes MemoryLevel[i] for * i < mclk_table.count (OOB for i >= 4) plus the unguarded * MemoryLevel[count-1] boot-watermark store. The clock-stretcher path * additionally READS GraphicsLevel[GraphicsDpmLevelCount-1]. * * Layout facts used below (smu72_discrete.h): GraphicsLevel is followed by * MemoryACPILevel (1 x MemoryLevel), then MemoryLevel[4]. */ #include <stdio.h> #define GLVLS 8 /* SMU72_MAX_LEVELS_GRAPHICS */ #define MLVLS 4 /* SMU72_MAX_LEVELS_MEMORY */ #define GLSZ 64 /* sizeof(SMU72_Discrete_GraphicsLevel) ~64B */ #define MLSZ 96 /* sizeof(SMU72_Discrete_MemoryLevel) ~96B */ int main(void) { uint32_t sclk_count = 16, mclk_count = 9; /* crafted VBIOS dep tables */ uint32_t gl_array = GLVLS * GLSZ; /* GraphicsLevel[8] span */ uint32_t i, oob = 0, worst = 0; for (i = 0; i < sclk_count; i++) { uint32_t off = i * GLSZ; if (off + GLSZ > gl_array) { oob++; worst = off + GLSZ; } } printf("GraphicsLevel[8] span : %u bytes\n", gl_array); printf("sclk dep count (VBIOS u8) : %u\n", sclk_count); printf("OOB GraphicsLevel writes : %u, worst write ends at GraphicsLevel+%u\n", oob, worst); printf(" -> stomps MemoryACPILevel/MemoryLevel[4]/LinkLevel[8]/... %s\n", worst > gl_array + (MLSZ * 5) + 400 ? "and beyond struct tonga_smumgr" : "(intra-struct)"); oob = 0; worst = 0; for (i = 0; i < mclk_count; i++) { uint32_t off = i * MLSZ; if (off + MLSZ > MLVLS * MLSZ) { oob++; worst = off + MLSZ; } } /* plus the unguarded MemoryLevel[count-1] watermark store */ uint32_t wm_off = (mclk_count - 1) * MLSZ; printf("MemoryLevel[4] span : %u bytes; mclk count %u\n", MLVLS * MLSZ, mclk_count); printf("OOB MemoryLevel writes : %u (worst ends at +%u); watermark store at +%u (also OOB)\n", oob, worst, wm_off); /* count==0 underflow form: MemoryLevel[0-1] */ printf("count==0 form : MemoryLevel[(uint32)(0-1)] = wild write at +4294967295*%u\n", MLSZ); return 1; /* corruption index math demonstrated */ } |