DragonFlyBSD Kernel Audit
DF-3078 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/ufs/ffs_vfsops.c
+++ b/sys/vfs/ufs/ffs_vfsops.c
@@ -486,6 +486,32 @@
 			brelse(bp);
 			return (EIO);		/* XXX needs translation */
 	}
 	fs = VFSTOUFS(mp)->um_fs;
 	/*
+	 * The cylinder-summary buffer (fs_csp), the maxcluster array and
+	 * fs_contigdirs were allocated at mount time for the geometry of
+	 * the superblock read then.  Step 3 below and the cluster-summary
+	 * refill write into those allocations using the geometry of the
+	 * re-read superblock, and ffs_sbupdate() copies fs_sbsize bytes
+	 * out of the mount-time um_fs allocation.  A re-read superblock
+	 * with different sizing geometry therefore writes or reads out of
+	 * the bounds of those allocations (kernel heap corruption and a
+	 * kernel-memory disclosure to the media).  Only superblocks whose
+	 * sizing geometry matches the mounted one may be adopted.
+	 */
+	if (newfs->fs_sbsize != fs->fs_sbsize ||
+	    newfs->fs_bsize != fs->fs_bsize ||
+	    newfs->fs_fsize != fs->fs_fsize ||
+	    newfs->fs_frag != fs->fs_frag ||
+	    newfs->fs_ncg != fs->fs_ncg ||
+	    newfs->fs_ipg != fs->fs_ipg ||
+	    newfs->fs_cssize != fs->fs_cssize ||
+	    newfs->fs_csaddr != fs->fs_csaddr ||
+	    newfs->fs_contigsumsize != fs->fs_contigsumsize ||
+	    newfs->fs_bshift != fs->fs_bshift ||
+	    newfs->fs_fshift != fs->fs_fshift) {
+		brelse(bp);
+		return (EINVAL);
+	}
+	/*
 	 * Copy pointer fields back into superblock before copying in	XXX
@@ -496,7 +496,8 @@
 	newfs->fs_maxcluster = fs->fs_maxcluster;
 	newfs->fs_contigdirs = fs->fs_contigdirs;
 	/* The filesystem is still read-only. */
 	newfs->fs_ronly = 1;
+	newfs->fs_fmod = 0;
 	bcopy(newfs, fs, (uint)fs->fs_sbsize);
 	if (fs->fs_sbsize < SBSIZE)
 		bp->b_flags |= B_INVAL;