⬢ DragonFlyBSD Kernel Audit
DF-3232 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/ufs/ffs_vfsops.c
+++ b/sys/vfs/ufs/ffs_vfsops.c
@@ -644,6 +644,36 @@
 		error = EINVAL;		/* XXX needs translation */
 		goto out;
 	}
+	/*
+	 * Validate the derived fragment/block geometry.  These fields feed
+	 * shift/mask arithmetic that indexes kernel memory (fragstoblks()
+	 * selects the byte inside the cylinder-group block bitmap in
+	 * ffs_subr.c; fragroundup()/blkoff() size and offset I/O buffers).
+	 * An inconsistent combination on crafted media scales those indexes
+	 * past the bitmap / buffer end (DF-3232) or rounds buffer sizes the
+	 * wrong way (DF-3190/DF-3212/DF-0903 family).
+	 */
+	if (fs->fs_fsize < DEV_BSIZE || fs->fs_fsize > fs->fs_bsize ||
+	    (fs->fs_fsize & (fs->fs_fsize - 1)) != 0 ||
+	    fs->fs_frag <= 0 || fs->fs_frag > MAXFRAG ||
+	    (fs->fs_frag & (fs->fs_frag - 1)) != 0 ||
+	    fs->fs_fragshift < 0 || fs->fs_fragshift >= 31 ||
+	    (1 << fs->fs_fragshift) != fs->fs_frag ||
+	    fs->fs_bsize != fs->fs_fsize << fs->fs_fragshift ||
+	    fs->fs_bshift < 0 || fs->fs_bshift >= 31 ||
+	    (1 << fs->fs_bshift) != fs->fs_bsize ||
+	    fs->fs_fshift < 0 || fs->fs_fshift >= 31 ||
+	    (1 << fs->fs_fshift) != fs->fs_fsize ||
+	    fs->fs_bmask != (int32_t)~(fs->fs_bsize - 1) ||
+	    fs->fs_fmask != (int32_t)~(fs->fs_fsize - 1) ||
+	    (fs->fs_inodefmt >= FS_44INODEFMT &&
+	     (fs->fs_qbmask != (int64_t)(fs->fs_bsize - 1) ||
+	      fs->fs_qfmask != (int64_t)(fs->fs_fsize - 1)))) {
+		kprintf("ffs_mountfs: %s: inconsistent fragment geometry\n",
+		    mp->mnt_stat.f_mntonname);
+		error = EINVAL;
+		goto out;
+	}
 	fs->fs_fmod = 0;
 	fs->fs_flags &= ~FS_UNCLEAN;
 	if (fs->fs_clean == 0) {