DF-0820 / fix.diff
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 @@ -593,7 +593,8 @@ struct fs *fs; cdev_t dev; void *space; - int error, i, blks, size, ronly; + int error, i, blks, ronly; + size_t size; int32_t *lp; uint64_t maxfilesize; /* XXX */ @@ -644,6 +645,27 @@ error = EINVAL; /* XXX needs translation */ goto out; } + /* + * DF-0820: validate superblock geometry before any of these fields is + * used as a divisor, an allocation size, or a loop bound. A crafted + * image could otherwise cause: divide-by-zero (fs_fsize/fs_frag/fs_ipg/ + * fs_fpg == 0), an unbounded bzero from a size_t-wrapped `size' + * (fs_ncg < 0 -> bzero(fs_contigdirs, (size_t)-1)), a controlled-value + * heap overflow from the maxcluster init loop (fs_ncg large enough that + * the `int size' allocation wrapped small), an out-of-bounds read in the + * superblock bcopy (fs_sbsize > SBSIZE), or reads past the kmalloc'd + * superblock copy (fs_sbsize < sizeof(struct fs)). + */ + if (fs->fs_sbsize < (int32_t)sizeof(struct fs) || + fs->fs_sbsize > SBSIZE || + fs->fs_fsize <= 0 || fs->fs_fsize > fs->fs_bsize || + fs->fs_frag <= 0 || (fs->fs_frag - 1) & fs->fs_frag || + fs->fs_ncg <= 0 || fs->fs_ncg > 1000000 || + fs->fs_ipg <= 0 || fs->fs_fpg <= 0 || + fs->fs_cssize < 0 || fs->fs_cssize > (1 << 30)) { + error = EINVAL; + goto out; + } fs->fs_fmod = 0; fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { |