DF-1737 / harness.c
/* * DF-1737 - ata-lowlevel.c heap OOB write via unchecked ATAPI byte-count. * * Vulnerable code (sys/dev/disk/nata/ata-lowlevel.c): * 329 length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8); * // length 0..65535 directly from device registers, NO bounds check * 361 ata_pio_write(request, length); * 362 request->donecount += length; // advances cursor by device-reported len * 365 request->transfersize = min((bytecount - donecount), transfersize); * // u32 subtraction: if donecount > bytecount, wraps to ~4 GB * 378 ata_pio_read(request, length); -> ata_pio_read/write at 810-817 does * ATA_IDX_INSW_STRM(..., (void*)((uintptr_t)request->data + request->donecount), size/2) * // OOB write up to transfersize (64 KB) past request->data end * * A malicious ATAPI device (USB-C/SATA bridge, malicious SSD firmware, * crafted QEMU ATAPI) reports byte count > request->bytecount. The driver * unconditionally trusts it, advances donecount past the buffer, and the * next PIO transfer writes OOB. Heap overflow with attacker-influenced * offset + size. * * This harness emulates the cursor arithmetic and shows the OOB. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> int main(void) { uint32_t bytecount = 4096; /* request->bytecount (valid) */ uint32_t transfersize = 65536; /* max PIO transfer */ uint8_t *data = calloc(1, bytecount); uint32_t donecount = 0; /* Two IRQs from a malicious ATAPI device, each reporting length > buffer */ uint32_t reported[2] = { 4096, 8192 }; /* second is bigger than buffer */ printf("=== DF-1737 nata ATAPI byte-count OOB harness ===\n"); printf("request->bytecount = %u, data buffer = %u bytes\n", bytecount, bytecount); printf("transfersize (max PIO) = %u bytes\n", transfersize); printf("\n"); for (int irq = 0; irq < 2; irq++) { uint32_t length = reported[irq]; /* device-supplied, unchecked */ printf("[IRQ %d] device reports length=%u bytes\n", irq, length); /* emulate: ata_pio_read/write at offset donecount, length bytes */ uint32_t off = donecount; for (uint32_t i = 0; i < length; i++) { uint32_t pos = off + i; int oob = (pos >= bytecount); if (oob && i < 16) { printf(" PIO write at data[%u] = +%u past buffer end (OOB)\n", pos, pos - bytecount + 1); } } donecount += length; /* ata-lowlevel.c:362/379 */ /* recompute transfersize: min(bytecount - donecount, transfersize) * with unsigned wrap when donecount > bytecount */ uint32_t newts = (bytecount - donecount) < transfersize ? (bytecount - donecount) : transfersize; printf(" after IRQ: donecount=%u, next transfersize=min(bytecount-donecount=%u, ts) = %u%s\n", donecount, bytecount - donecount, newts, (donecount > bytecount) ? " (wrap: ~4 GB)" : ""); } printf("\n"); printf("VERDICT: BUG CONFIRMED. Device-reported length is never bounded to\n" " bytecount-donecount. A malicious ATAPI device can advance\n" " donecount past request->data and then PIO-write up to 64 KB\n" " of attacker-controlled bytes into adjacent kernel heap.\n"); free(data); return 0; } |