DF-1183 / harness.c
/* * DF-1183 harness: demonstrates the missing count check in * vega10_get_soc_index_for_max_uclk() at vega10_hwmgr.c:3444-3453 * * The function indexes vdd_dep_on_mclk->entries[NUM_UCLK_DPM_LEVELS - 1] * unconditionally, but the table is allocated for ucNumEntries slots * (from VBIOS u8). If ucNumEntries < NUM_UCLK_DPM_LEVELS (4), the * hardcoded [3] is an OOB read. * * NUM_UCLK_DPM_LEVELS == 4 (sys/dev/drm/amd/powerplay/inc/smu9_driver_if.h:41). * * Allocation (vega10_processpptables.c:565-569): * table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) * ucNumEntries; * mclk_table = kzalloc(table_size, GFP_KERNEL); * * Caller chain (vega10_hwmgr.c): * vega10_upload_dpm_bootup_level() at line 3476-3477: * if (data->smc_state_table.mem_boot_level == NUM_UCLK_DPM_LEVELS - 1) * socclk_idx = vega10_get_soc_index_for_max_uclk(hwmgr); * * Compile: cc -O2 -o harness harness.c * Run: ./harness */ #include <stdio.h> #include <stdint.h> #include <stdlib.h> #define NUM_UCLK_DPM_LEVELS 4 struct mclk_record { uint8_t vddInd; uint8_t pad[3]; uint32_t clk; uint32_t memclk; }; struct mclk_table { uint32_t count; struct mclk_record entries[1]; }; static struct mclk_table *alloc_mclk(unsigned n) { size_t sz = sizeof(uint32_t) + sizeof(struct mclk_record) * n; struct mclk_table *t = calloc(1, sz); if (!t) { perror("calloc"); exit(1); } t->count = n; return t; } /* Faithful transcription of vega10_get_soc_index_for_max_uclk: no check. */ static int buggy_index(struct mclk_table *t) { return t->entries[NUM_UCLK_DPM_LEVELS - 1].vddInd + 1; } /* Fixed version: validate count first. */ static int fixed_index(struct mclk_table *t) { if (t->count < NUM_UCLK_DPM_LEVELS) return -1; return t->entries[NUM_UCLK_DPM_LEVELS - 1].vddInd + 1; } int main(void) { /* VBIOS with only 2 MCLK entries (ucNumEntries = 2). */ struct mclk_table *t = alloc_mclk(2); printf("== buggy ==\n"); printf("vega10_get_soc_index_for_max_uclk hardcoded " "entries[%d] but count=%u => OOB read (CWE-125)\n", NUM_UCLK_DPM_LEVELS - 1, t->count); printf("Returned index (garbage, from past-allocation bytes): %d\n", buggy_index(t)); printf("\n== fixed ==\n"); printf("Fixed version returns %d (validated count < %d)\n", fixed_index(t), NUM_UCLK_DPM_LEVELS); printf("\n=== DF-1183 logic-level result ===\n"); printf("Hardcoded entries[3] without count check on a table allocated\n"); printf("for ucNumEntries slots. Malicious VBIOS with ucNumEntries<4\n"); printf("reads kernel heap. Path runs only when amdgpu powerplay is\n"); printf("attached to a real Vega10 GPU - no AMD HW on this guest.\n"); free(t); return 0; } |