DF-3212 / fix.diff
--- a/sys/vfs/ufs/ufs_readwrite.c +++ b/sys/vfs/ufs/ufs_readwrite.c @@ -139,6 +139,23 @@ * Calculate how much data we can copy */ blkoffset = blkoff(fs, uio->uio_offset); + /* + * DF-3212: blkoffset is derived from the on-disk geometry + * (fs_qbmask) while b_bufsize is what ffs_blkatoff_ra() + * actually allocated (blksize(): fs_bsize, or the frag + * roundup of EOF). A crafted superblock can make the former + * exceed the latter, so xfersize would go negative below. + * The clamp against the unsigned uio_resid then silently + * converts that negative value into a small positive + * transfer (the "xfersize <= 0" panic guard further down is + * dead code for exactly this case), and uiomovebp() reads + * past the buffer into adjacent buffer-cache KVA. Reject + * the impossible geometry instead. + */ + if (blkoffset >= bp->b_bufsize) { + error = EIO; + break; + } xfersize = bp->b_bufsize - blkoffset; if (xfersize > uio->uio_resid) xfersize = uio->uio_resid; |