/*
 * DF-1783 - radeon_bios.c heap overflow in radeon_atrm_call:
 *           unbounded memcpy of ACPI-returned buffer into 256 KB bios buffer.
 *
 * Vulnerable code (sys/dev/drm/radeon/radeon_bios.c):
 *   207  memcpy(bios+offset, obj->Buffer.Pointer, obj->Buffer.Length);
 *        // uses ACPI-returned Length, NOT the caller's len arg
 *   208  len = obj->Buffer.Length;
 *
 * No obj->Type == ACPI_TYPE_BUFFER check. ACPI_OBJECT is a union; if the
 * method returns an Integer/String, Buffer.Pointer/Length alias other
 * union fields -> wild pointer / wild length.
 *
 * Caller (radeon_atrm_get_bios at line 269) allocates 256*1024, then
 * loops i=0..63 calling radeon_atrm_call(..., i*4096, 4096). At i=63,
 * offset = 63*4096 = 258048; the buffer has 256*1024-258048 = 4096 bytes
 * left. If the ACPI method returns a buffer with Length > 4096 at i=63,
 * memcpy overflows rdev->bios by (Length - 4096) bytes into adjacent heap.
 *
 * The only upper bound check at line 281 is `if (ret < ATRM_BIOS_PAGE)
 * break;` which catches short reads but NOT over-long ones.
 *
 * Trigger: malicious platform firmware / custom SSDT / PCI option ROM
 * installing a malicious _ATRM method.
 *
 * This harness simulates the i=63 case.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define ATRM_BIOS_PAGE 4096
#define BIOS_SIZE      (256 * 1024)

int main(void)
{
    uint8_t *bios = malloc(BIOS_SIZE);
    memset(bios, 0, BIOS_SIZE);

    printf("=== DF-1783 radeon_atrm_call heap overflow harness ===\n");
    printf("rdev->bios = malloc(%d)  [radeon_bios.c:269]\n", BIOS_SIZE);
    printf("\n");

    /* emulate the buggy caller loop at radeon_bios.c:275-283 */
    long total = 0;
    int overflows = 0;
    for (int i = 0; i < BIOS_SIZE / ATRM_BIOS_PAGE; i++) {
        long offset = (long)i * ATRM_BIOS_PAGE;
        /* Malicious _ATRM returns 8192 bytes at i=63 (the last iter) */
        long acpi_len = (i == 63) ? 8192 : 4096;
        long space = BIOS_SIZE - offset;
        printf("i=%2d: offset=%ld, ACPI len=%ld, space left=%ld%s\n",
               i, offset, acpi_len, space,
               (acpi_len > space) ? "  <-- OVERFLOW" : "");
        if (acpi_len > space) overflows++;
        /* buggy memcpy uses ACPI Length unconditionally */
        long copy = acpi_len;     /* line 207: obj->Buffer.Length */
        if (offset + copy > BIOS_SIZE) {
            printf("        memcpy writes %ld bytes past rdev->bios end!\n",
                   offset + copy - BIOS_SIZE);
        }
        total += copy;
        if (acpi_len < ATRM_BIOS_PAGE) break;   /* line 281: only catches SHORT */
    }
    printf("\n");
    if (overflows > 0) {
        printf("VERDICT: BUG CONFIRMED. radeon_atrm_call memcpy uses the\n"
               "        ACPI-returned Length without clamping to the caller's\n"
               "        `len` argument or checking obj->Type==BUFFER. A malicious\n"
               "        _ATRM method overflows rdev->bios (256 KB) at i=63.\n");
        free(bios);
        return 0;
    }
    printf("VERDICT: not reproduced.\n");
    free(bios);
    return 1;
}
