DragonFlyBSD Kernel Audit
DF-2675 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 1111111..2222222 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -2734,7 +2734,18 @@ getblk(struct vnode *vp, off_t loffset, int size, int blkflags, int slptimeo)
 	int lkflags;
 
-	if (size > MAXBSIZE)
-		panic("getblk: size(%d) > MAXBSIZE(%d)", size, MAXBSIZE);
+	/*
+	 * DF-2675: each buffer header owns a fixed KVA slot of exactly
+	 * MAXBSIZE bytes ([b_kvabase, b_kvabase + MAXBSIZE)).  allocbuf()
+	 * maps desiredpages = pages((loffset & PAGE_MASK) + roundup2(size,
+	 * DEV_BSIZE)) at b_kvabase, so an unaligned loffset makes the
+	 * mapping need MORE than MAXBSIZE bytes and pmap_qenter() writes
+	 * one PTE into the NEXT header's slot.  Bound the combination.
+	 */
+	if (size + (int)(loffset & PAGE_MASK) > MAXBSIZE)
+		panic("getblk: size(%d)+pgoff(%d) > MAXBSIZE(%d)",
+		      size, (int)(loffset & PAGE_MASK), MAXBSIZE);
 	if (vp->v_object == NULL)
 		panic("getblk: vnode %p has no object!", vp);
@@ -3037,8 +3048,12 @@ allocbuf(struct buf *bp, int size)
 	if (BUF_LOCKINUSE(bp) == 0)
 		panic("allocbuf: buffer not busy");
 
-	if (bp->b_kvasize < size)
-		panic("allocbuf: buffer too small");
+	/* DF-2675: defense in depth - account for the page offset. */
+	if (bp->b_kvasize < size + (int)(bp->b_loffset & PAGE_MASK))
+		panic("allocbuf: buffer too small (KVA slot overflow)");
 
 	KKASSERT(bp->b_flags & B_VMIO);
diff --git a/sys/vfs/msdosfs/msdosfs_vfsops.c b/sys/vfs/msdosfs/msdosfs_vfsops.c
index 3333333..4444444 100644
--- a/sys/vfs/msdosfs/msdosfs_vfsops.c
+++ b/sys/vfs/msdosfs/msdosfs_vfsops.c
@@ -507,6 +507,20 @@ msdosfs_vfsops.c: after pm_cnshift is computed
 	pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
 	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
 	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
+
+	/*
+	 * DF-2675: a MAXBSIZE-sized cluster whose device offset is not
+	 * page-aligned makes getblk()/allocbuf() map MAXBSIZE/PAGE_SIZE+1
+	 * pages into a MAXBSIZE per-header KVA slot, silently overwriting
+	 * the next buffer header's pmap mapping (cross-buffer aliasing).
+	 * Reject the mount instead (64KB clusters remain supported when
+	 * the data area is page-aligned).
+	 */
+	if (pmp->pm_bpcluster >= MAXBSIZE &&
+	    (((off_t)pmp->pm_firstcluster << pmp->pm_bnshift) & PAGE_MASK) != 0) {
+		kprintf("msdosfs: 64KB clusters at non-page-aligned "
+			"device offset %jd\n",
+			(intmax_t)((off_t)pmp->pm_firstcluster << pmp->pm_bnshift));
+		error = EINVAL;
+		goto error_exit;
+	}
 
 	/*
 	 * Check for valid cluster size