DF-3078 / fix.diff
--- 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; |