DF-0903 / promote_test.c
/* Verify the C promotion semantics that defeat DF-0903's claimed chain. * `uio->uio_resid` is `size_t` (unsigned, sys/sys/_uio.h:69). * `xfersize` is `int` (signed, ufs_readwrite.c:220). * Line 294: `if (uio->uio_resid < xfersize)` -- the int is promoted to size_t, * turning negative xfersize into a huge value, so the comparison is TRUE and * line 295 clamps xfersize to uio_resid (a small positive). The negative * xfersize NEVER reaches line 356's uiomove. */ #include <stdio.h> #include <stdint.h> #include <stddef.h> int main(void){ int fs_bsize = 8192; int blkoffset = 10000; /* from crafted fs_qbmask */ int xfersize = fs_bsize - blkoffset; /* -1808 */ size_t uio_resid = 16; /* from pwrite(fd,buf,16,10000) */ printf("xfersize (int) = %d\n", xfersize); printf("(size_t)xfersize = 0x%016zx (%zu)\n", (size_t)xfersize, (size_t)xfersize); printf("uio_resid = %zu\n", uio_resid); /* The kernel comparison: */ if (uio_resid < xfersize) { /* size_t < int -> int promoted to size_t */ printf("LINE 294: uio_resid < xfersize is TRUE (size_t promotion)\n"); printf("LINE 295: xfersize = uio_resid = %zu\n", uio_resid); xfersize = (int)uio_resid; /* clamped to 16 */ } printf("xfersize after clamp = %d (POSITIVE -- OOB path defeated)\n", xfersize); /* balloc size check: */ int balloc_size = blkoffset + xfersize; /* 10000 + 16 = 10016 */ printf("balloc: blkoffset + xfersize = %d + %d = %d > fs_bsize=%d => PANIC 'blk too big'\n", blkoffset, xfersize, balloc_size, fs_bsize); return 0; } |