DF-4611 / buftop_prover.c
/* * DF-4611 offset-math prover — neomagic nm_init() trusts card-provided * buftop (neomagic.c:576-588). * * Reproduces, in portable userland, the exact arithmetic nm_init() runs * after the card-memory override * * ofs = buftop - 0x0400; * buftop-= 0x1400; * if (signature@ofs == NM_SIGNATURE && (i = read@ofs+4) != 0/0xffffffff) * buftop = i; <- unvalidated card value * cbuf = buftop - 0x5000; * rbuf = cbuf - 0x4000; * pbuf = rbuf - 0x4000; * acbuf = pbuf - 0x3158*4; * * and prints, for hostile buftop values, the offsets later fed to * bus_space_write (nm_loadcoeff: sc->cbuf + i, i up to 0x4fff) and to * sndbuf_setup (rman_get_virtual(sc->buf) + chnbuf) -- i.e. how far * BELOW the BAR mapping kernel writes would land. * * The kernel-side trigger needs real NM256 hardware whose buffer-memory * signature block returns a crafted `i`; the audit guest has no such * function (QEMU 7.2 has no NM256 model), so this prover documents the * corruption arithmetic instead of the kernel write itself. */ #include <stdio.h> #include <stdint.h> int main(void) { static const uint32_t hostile[] = { 0x00000100, /* absurdly small */ 0x00000fff, /* below minimum needed */ 0x0000beef, /* garbage */ 0x0001b95f, /* one byte below the true minimum 0x1b960 */ 0x00100000, /* 1MB - fine on paper, truncated card */ }; uint32_t sane[] = { 0x400000, 0x600000 }; /* ZX legit values */ size_t k; printf("%-10s %-10s %-10s %-10s %-10s %s\n", "buftop", "cbuf", "rbuf", "pbuf", "acbuf", "verdict"); for (k = 0; k < sizeof(hostile) / sizeof(hostile[0]); k++) { uint32_t bt = hostile[k] - 0x1400; uint32_t cbuf = bt - 0x5000, rbuf = cbuf - 0x4000, pbuf = rbuf - 0x4000, acbuf = pbuf - 0x3158 * 4; int wraps = (cbuf >> 31) | (rbuf >> 31) | (pbuf >> 31) | (acbuf >> 31); printf("%08x %08x %08x %08x %08x %s\n", bt, cbuf, rbuf, pbuf, acbuf, wraps ? "WRAPS -> ~4G OOB bus_space offset" : "below 0x1b960 -> overlaps regs/coeff areas"); } for (k = 0; k < sizeof(sane) / sizeof(sane[0]); k++) { uint32_t bt = sane[k] - 0x1400; uint32_t cbuf = bt - 0x5000, rbuf = cbuf - 0x4000, pbuf = rbuf - 0x4000, acbuf = pbuf - 0x3158 * 4; printf("%08x %08x %08x %08x %08x %s\n", bt, cbuf, rbuf, pbuf, acbuf, "in range (legit)"); } printf("\nminimum sane buftop = 0x1400+0x5000+2*0x4000+0x3158*4 = 0x1b960\n"); return 0; } |