DF-3784 / harness_vbi_read.c
/* * DF-3784 -- vbi_read() 64-bit iov_len truncated to int -> negative readsize * -> uiomove(vbibuffer+start, (size_t)INT_MIN) -> mass kernel leak * * Source-level harness porting the exact decision logic of * sys/dev/video/bktr/bktr_core.c:1124-1194 (vbi_read) and the length * arithmetic of sys/kern/kern_subr.c uiomove(). */ #include <stdio.h> #include <sys/types.h> #define VBI_BUFFER_SIZE (2048 * 16 * 2 * 20) /* bktr_core.c:174 */ int main(void) { int readsize, readsize2, start; int vbistart = 0, vbisize = 65536; /* one decoded VBI frame present */ size_t iov_len = 0x80000000UL; /* read(fd, buf, 2GB): legal */ size_t n; /* uiomove's size_t parameter */ printf("iov_len (read() 3rd arg) = 0x%zx (valid: (ssize_t)>0)\n", iov_len); /* ---- bktr_core.c:1159-1161 ---- */ readsize = (int)iov_len; printf("vbi_read: readsize = (int)iov_len = %d\n", readsize); if (readsize > vbisize) readsize = vbisize; printf("clamp 'if (readsize > vbisize)' -> readsize still %d " "(negative, clamp skipped)\n", readsize); /* ---- bktr_core.c:1165-1178 ---- */ if ((vbistart + readsize) >= VBI_BUFFER_SIZE) { printf("wrap branch taken (unexpected)\n"); return 1; } printf("wrap check '(vbistart+readsize) >= VBI_BUFFER_SIZE': %d >= %d " "-> false, straight-through branch\n", vbistart + readsize, VBI_BUFFER_SIZE); /* ---- bktr_core.c:1177: uiomove(vbibuffer + vbistart, readsize, uio) * kern_subr.c uiomove(caddr_t, size_t n, ...): int -> size_t ---- */ n = (size_t)readsize; printf("uiomove n = (size_t)(int)0x80000000 = 0x%zx (%zu)\n", n, n); /* ---- kern_subr.c uiomove loop: cnt = MIN(iov_len, n) ---- */ { size_t cnt = iov_len; if (cnt > n) cnt = n; printf("uiomove cnt = MIN(iov_len=2GB, n) = %zu bytes " "copied from vbibuffer+0 to user buffer\n", cnt); printf("=> 2 GiB of kernel virtual memory disclosed from " "vbibuffer upward until first unmapped page (EFAULT " "stops it; partial data already in user buffer)\n"); } /* ---- state corruption: bktr_core.c:1183-1187 ---- */ vbisize -= readsize; vbistart += readsize; printf("post-state: vbisize=%d vbistart=%d (both corrupted by int " "overflow)\n", vbisize, vbistart); printf("CONFIRMED: no guard rejects a negative readsize in vbi_read\n"); return 0; } |