DF-3232 / fix.diff
--- 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) { |