DragonFlyBSD Kernel Audit
DF-0919 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/ufs/ffs_vfsops.c b/sys/vfs/ufs/ffs_vfsops.c
--- a/sys/vfs/ufs/ffs_vfsops.c
+++ b/sys/vfs/ufs/ffs_vfsops.c
@@ -486,6 +486,20 @@
 			brelse(bp);
 			return (EIO);		/* XXX needs translation */
 	}
+	/*
+	 * Validate fs_frag for the same reasons as ffs_mountfs(): it indexes
+	 * fixed-size tables and discriminates the bitmap helpers in ffs_subr.c.
+	 */
+	switch ((int)newfs->fs_frag) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		break;
+	default:
+		brelse(bp);
+		return (EIO);
+	}
 	fs = VFSTOUFS(mp)->um_fs;
 	/*
 	 * Copy pointer fields back into superblock before copying in	XXX
@@ -644,6 +658,23 @@
 		error = EINVAL;		/* XXX needs translation */
 		goto out;
 	}
+	/*
+	 * fs_frag indexes fixed-size lookup tables (fragtbl[], around[],
+	 * inside[], cg_frsum[]) and is the switch discriminator of the
+	 * block-bitmap helpers in ffs_subr.c.  Any value outside {1,2,4,8}
+	 * would panic the kernel on the first block alloc/free (DoS) and,
+	 * for fs_frag > MAXFRAG, drives out-of-bounds writes in ffs_fragacct().
+	 */
+	switch ((int)fs->fs_frag) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		break;
+	default:
+		error = EINVAL;
+		goto out;
+	}
 	fs->fs_fmod = 0;
 	fs->fs_flags &= ~FS_UNCLEAN;
 	if (fs->fs_clean == 0) {
diff --git a/sys/vfs/ufs/ffs_subr.c b/sys/vfs/ufs/ffs_subr.c
--- a/sys/vfs/ufs/ffs_subr.c
+++ b/sys/vfs/ufs/ffs_subr.c
@@ -167,6 +167,15 @@
 	int siz, pos;
 
 	/*
+	 * Defense-in-depth: fragtbl[], around[], inside[], and cg_frsum[]
+	 * are sized for fs_frag in [1, MAXFRAG].  ffs_mountfs() should have
+	 * rejected anything else, but bail out here too so a future caller
+	 * or a missed path cannot drive an out-of-bounds table access.
+	 */
+	if (fs->fs_frag <= 0 || fs->fs_frag > MAXFRAG)
+		return;
+
+	/*
 	 * inblk represents a bitmap of fragment sizes which may be
 	 * contained in the data 'fragmap'.  e.g. if a fragment of size
 	 * 1 is available, bit 0 would be set.  inblk is shifted left