⬢ DragonFlyBSD Kernel Audit
DF-3212 / fix.diff
← back to finding ↓ download raw
--- 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;