/* DF-1535/DF-1543: atom FB scratch u32 wrap OOB harness.
 * Replicates: gctx->scratch[(fb_base/4)+idx] guarded by
 *   if ((fb_base + idx*4) > scratch_size_bytes)
 * fb_base is u32. With fb_base=0xFFFFFFFC idx=1, sum wraps to 0 (passes
 * guard), then access at scratch[(fb_base/4)+idx] = scratch[0x3FFFFFFF+1]
 * is a wild OOB.
 */
#include <stdio.h>
#include <stdint.h>
#include <string.h>

static int scratch_size_bytes = 20480;
static int fixed = 0;

static int atom_fb_read(uint32_t fb_base, uint8_t idx) {
    /* original buggy: u32+u32 wraps */
    if (!fixed) {
        if ((fb_base + (idx * 4)) > (uint32_t)scratch_size_bytes) {
            return -1;  /* rejected */
        }
    } else {
        /* patched: u64 math */
        if ((uint64_t)fb_base + (uint64_t)(idx * 4) > (uint64_t)scratch_size_bytes) {
            return -1;
        }
    }
    /* would access gctx->scratch[(fb_base/4) + idx] */
    uint32_t dword_off = (fb_base / 4) + idx;
    printf("  access scratch[%u] (alloc dwords=5120)\n", dword_off);
    return (int)dword_off;
}

int main(int argc, char **argv) {
    if (argc > 1 && !strcmp(argv[1], "--fixed")) fixed = 1;

    /* attacker scenario: VBIOS sets fb_base = 0xFFFFFFFC via WS[FB_WINDOW] */
    uint32_t evil_fb = 0xFFFFFFFC;
    uint8_t evil_idx = 1;
    printf("scratch_size_bytes=%d (alloc dwords=5120)\n", scratch_size_bytes);
    int rc = atom_fb_read(evil_fb, evil_idx);
    if (fixed)
        printf("RESULT: PATCHED - u64 guard rejects fb_base=0x%x idx=%u\n",
               evil_fb, evil_idx);
    else if (rc < 0)
        printf("RESULT: BUG (no overflow seen)\n");
    else
        printf("RESULT: BUGGY - guard bypassed (0xFFFFFFFC + 4 = 0 wraps to 0 <= 20480)\n");
    return 0;
}
