/*
 * DF-1894 source-confirmation harness (i915 DMC firmware fw_size*4 overflow).
 *
 * sys/dev/drm/i915/intel_csr.c:404-425 parse_csr_fw:
 *   nbytes = dmc_header->fw_size * 4;              // uint32 mult — wraps
 *   if (nbytes > max_fw_size) return NULL;          // tests wrapped value
 *   csr->dmc_fw_size = dmc_header->fw_size;         // stores ORIGINAL (huge)
 *   dmc_payload = kmalloc(nbytes, ...);             // tiny alloc
 *   return memcpy(dmc_payload, &fw->data[off], nbytes);  // tiny copy — ok
 *
 * Then intel_csr_load_program (intel_csr.c:259-265):
 *   fw_size = csr->dmc_fw_size;                     // 0x40000001
 *   for (i = 0; i < fw_size; i++)
 *       I915_WRITE_FW(CSR_PROGRAM(i), payload[i]);  // payload[i] OOB read
 *
 * With fw_size = 0x40000001: nbytes wraps to 4, kmalloc(4) succeeds,
 * 4-byte memcpy is fine, but the load_program loop reads ~10^9 dwords
 * past payload[] into kernel heap, writing each to MMIO.
 *
 * Needs root-controlled firmware path (module param dmc_firmware_path,
 * mode 0400) — not unpriv-reachable on this guest.  The harness shows
 * the wrap arithmetic.
 *
 * Build:  cc -O2 -o harness harness.c
 * Run:    ./harness
 */
#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint32_t fw_size = 0x40000001u;
    uint32_t nbytes  = fw_size * 4;        /* intel_csr.c:404 — wraps mod 2^32 */
    uint32_t max_fw  = 0x100000;           /* BXT_CSR_MAX_FW_SIZE ~1MB */

    printf("DF-1894: parse_csr_fw (intel_csr.c:404-425) + intel_csr_load_program (:259)\n");
    printf("  dmc_header->fw_size = 0x%08x\n", fw_size);
    printf("  nbytes = fw_size * 4 = 0x%08x (WRAPS — should be 0x%llx)\n",
           nbytes, (unsigned long long)fw_size * 4);
    printf("  nbytes > max_fw_size (0x%x)? %s\n", max_fw,
           nbytes > max_fw ? "YES (reject)" : "NO (check bypassed)");
    printf("  -> kmalloc(%u) succeeds; memcpy %u bytes is fine\n", nbytes, nbytes);
    printf("  -> csr->dmc_fw_size = 0x%08x (ORIGINAL, not wrapped)\n", fw_size);
    printf("  -> intel_csr_load_program loops i=0..0x%08x calling I915_WRITE_FW "
           "(CSR_PROGRAM(i), payload[i])\n", fw_size);
    printf("     payload has %u bytes allocated; reads ~%u dwords past it into "
           "kernel heap -> OOB read + MMIO corruption -> GPU/CPU wedge\n",
           nbytes, fw_size - (nbytes/4));
    return 0;
}
