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