DF-4000 / trigger_analysis.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | /* * DF-4000 — index-math demonstrator for the iceland (Topaz) SMC table * populate walks (sys/dev/drm/amd/powerplay/smumgr/iceland_smumgr.c). * * Provenance of the loop bounds (all attacker-controlled only through a * crafted GPU VBIOS PowerPlay table — hardware-gated, like DF-3908/3940): * * ATOM PowerPlay dep table ucNumEntries (u8, unclamped) * -> hwmgr->dyn_state.vddc_dependency_on_{s,m}clk->count * (processpptables.c:391 get_clock_voltage_dependency_table) * -> data->dpm_table.{s,m}clk_table.count * (smu7_hwmgr.c:689-697 / 704-711 smu7_setup_dpm_tables_v0, no clamp; * Topaz pinned to PP_TABLE_V0 at hwmgr.c:114-122) * -> loop bounds in iceland_smumgr.c * * Sinks and their array bounds (smu71.h / smu71_discrete.h): * smc_state_table.GraphicsLevel[SMU71_MAX_LEVELS_GRAPHICS = 8] * iceland_populate_all_graphic_levels iceland_smumgr.c:980-990 * (plus [count-1] store at 997 and pcieDpmLevel writes at 1026-1028) * smc_state_table.MemoryLevel[SMU71_MAX_LEVELS_MEMORY = 4] * iceland_populate_all_memory_levels iceland_smumgr.c:1361-1369 * (plus [count-1] store at 1385) * STACK object SMU71_Discrete_MCArbDramTimingTable: * entries[SMU__NUM_SCLK_DPM_STATE=8][SMU__NUM_MCLK_DPM_LEVELS=4] * iceland_program_memory_timing_parameters iceland_smumgr.c:1616-1632 * mc_regs.data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT = 4] * iceland_convert_mc_reg_table_to_smc iceland_smumgr.c:1761-1766 * (+ upload of sizeof(MCRegisterSet)*count at 1796-1799) * * The struct replicas below are verbatim from smu71_discrete.h so the * sizeof/offset arithmetic is the kernel's own. */ #include <stdio.h> #include <stdint.h> #include <stddef.h> #include <string.h> #define SMU__NUM_SCLK_DPM_STATE 8 #define SMU__NUM_MCLK_DPM_LEVELS 4 #define SMU71_MAX_LEVELS_GRAPHICS SMU__NUM_SCLK_DPM_STATE #define SMU71_MAX_LEVELS_MEMORY SMU__NUM_MCLK_DPM_LEVELS #define SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE 16 #define SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT SMU71_MAX_LEVELS_MEMORY /* --- verbatim struct replicas (smu71_discrete.h:47-74,110-149,167-181) --- */ struct SMU71_Discrete_GraphicsLevel { uint32_t MinVddc, MinVddcPhases, SclkFrequency; uint8_t pcieDpmLevel, DeepSleepDivId; uint16_t ActivityLevel; uint32_t CgSpllFuncCntl3, CgSpllFuncCntl4, SpllSpreadSpectrum, SpllSpreadSpectrum2, CcPwrDynRm, CcPwrDynRm1; uint8_t SclkDid, DisplayWatermark, EnabledForActivity, EnabledForThrottle, UpHyst, DownHyst, VoltageDownHyst, PowerThrottle; }; struct SMU71_Discrete_MemoryLevel { uint32_t MinVddc, MinVddcPhases, MinVddci, MinMvdd, MclkFrequency; uint8_t EdcReadEnable, EdcWriteEnable, RttEnable, StutterEnable, StrobeEnable, StrobeRatio, EnabledForThrottle, EnabledForActivity, UpHyst, DownHyst, VoltageDownHyst, padding; uint16_t ActivityLevel; uint8_t DisplayWatermark, padding1; uint32_t MpllFuncCntl, MpllFuncCntl_1, MpllFuncCntl_2, MpllAdFuncCntl, MpllDqFuncCntl, MclkPwrmgtCntl, DllCntl, MpllSs1, MpllSs2; }; struct SMU71_Discrete_MCArbDramTimingTableEntry { uint32_t McArbDramTiming, McArbDramTiming2; uint8_t McArbBurstTime; uint8_t padding[3]; }; struct SMU71_Discrete_MCArbDramTimingTable { struct SMU71_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS]; }; int main(void) { size_t gl = sizeof(struct SMU71_Discrete_GraphicsLevel); size_t ml = sizeof(struct SMU71_Discrete_MemoryLevel); size_t ar = sizeof(struct SMU71_Discrete_MCArbDramTimingTable); unsigned sclk_count = 12; /* crafted VBIOS ucNumEntries (u8, 1..255) */ unsigned mclk_count = 6; unsigned i, j, oob; printf("sizeof: GraphicsLevel=%zu MemoryLevel=%zu MCArbDramTimingTable" "=%zu (stack) MCRegisterSet.data entries=%d\n", gl, ml, ar, SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT); printf("crafted VBIOS: sclk dep ucNumEntries=%u mclk dep ucNumEntries=%u" " (both pass unclamped through processpptables.c:391 and" " smu7_hwmgr.c:689-711)\n\n", sclk_count, mclk_count); /* iceland_populate_all_graphic_levels: for (i = 0; i < count; i++) * GraphicsLevel[i] = ...; array bound: 8 */ oob = 0; for (i = 0; i < sclk_count; i++) { if (i >= SMU71_MAX_LEVELS_GRAPHICS) { oob++; if (oob == 1) printf("GraphicsLevel[%u]: +%zu bytes past the" " GraphicsLevel[8] array", i, (i - SMU71_MAX_LEVELS_GRAPHICS) * gl + gl); } } printf(" -> %u/%u GraphicsLevel writes OOB (max +%zu bytes past the" " array end, walking MemoryACPILevel/MemoryLevel/LinkLevel/" "ACPILevel/Smio and beyond inside smc_state_table)\n", oob, sclk_count, (sclk_count - SMU71_MAX_LEVELS_GRAPHICS) * gl); printf(" -> GraphicsLevel[count-1] store at :997 indexes [%u]\n", sclk_count - 1); /* iceland_populate_all_memory_levels: MemoryLevel[i], array bound: 4 */ oob = 0; for (i = 0; i < mclk_count; i++) { if (i >= SMU71_MAX_LEVELS_MEMORY) { oob++; if (oob == 1) printf("MemoryLevel[%u]: +%zu bytes past the" " MemoryLevel[4] array", i, (i - SMU71_MAX_LEVELS_MEMORY) * ml + ml); } } printf(" -> %u/%u MemoryLevel writes OOB (max +%zu bytes past the" " array end, walking LinkLevel/ACPILevel/...; smc_state_table is" " followed by power_tune_table/ulv_setting/mc_regs/mc_reg_table" " inside the kzalloc'd iceland_smumgr)\n", oob, mclk_count, (mclk_count - SMU71_MAX_LEVELS_MEMORY) * ml); printf(" -> MemoryLevel[count-1] store at :1385 indexes [%u]\n", mclk_count - 1); /* iceland_program_memory_timing_parameters: STACK * arb_regs.entries[i][j], i < sclk_count, j < mclk_count */ oob = 0; for (i = 0; i < sclk_count; i++) { for (j = 0; j < mclk_count; j++) { size_t lin = (size_t)i * SMU__NUM_MCLK_DPM_LEVELS + j; if (lin >= SMU__NUM_SCLK_DPM_STATE * SMU__NUM_MCLK_DPM_LEVELS) { oob++; if (oob == 1) printf("arb_regs.entries[%u][%u]: linear entry %zu" " of 32 -> +%zu bytes past the %zu-byte" " STACK object", i, j, lin, (lin - 31) * sizeof(struct SMU71_Discrete_MCArbDramTimingTableEntry), ar); } } } printf(" -> %u of %u stack-table writes OOB (max linear entry %zu," " i.e. +%zu bytes past the stack object)\n", oob, sclk_count * mclk_count, (size_t)(sclk_count - 1) * SMU__NUM_MCLK_DPM_LEVELS + (mclk_count - 1), ((size_t)(sclk_count - 1) * SMU__NUM_MCLK_DPM_LEVELS + (mclk_count - 1) - 31) * sizeof(struct SMU71_Discrete_MCArbDramTimingTableEntry)); /* iceland_convert_mc_reg_table_to_smc: mc_regs->data[i], bound 4 */ oob = 0; for (i = 0; i < mclk_count; i++) { if (i >= SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT) oob++; } printf(" -> %u/%u mc_regs.data[] writes OOB (past data[4] into the" " rest of SMU71_Discrete_MCRegisters / iceland_smumgr), plus" " smu7_copy_bytes_to_smc of sizeof(MCRegisterSet)*%u at :1798" " reads past mc_regs\n", oob, mclk_count, mclk_count); /* and note the upstream construction already overflows its own array: * dpm_levels[MAX_REGULAR_DPM_NUMBER = 8] (smu7_hwmgr.h:100) */ printf("\nupstream: smu7_setup_dpm_tables_v0 also writes" " dpm_levels[%u..%u] past dpm_levels[8]" " (smu7_hwmgr.c:689-711; DF-1166)\n", SMU71_MAX_LEVELS_GRAPHICS, sclk_count - 1); printf("DONE (source-certain; kernel fault itself hardware-gated -" " needs a Topaz/ICELAND GPU with the crafted VBIOS)\n"); return 0; } |