diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include +#include #ifndef _KERNEL #include @@ -50,6 +51,7 @@ struct malloc_type; #define UFS_MALLOC(size, type, flags) malloc(size) #define UFS_FREE(ptr, type) free(ptr) +#define maxphys MAXPHYS #else /* _KERNEL */ #include @@ -125,6 +127,7 @@ static off_t sblock_try[] = SBLOCKSEARCH; static int readsuper(void *, struct fs **, off_t, int, int, int (*)(void *, off_t, void **, int)); +static int validate_sblock(struct fs *, int); /* * Read a superblock from the devfd device. @@ -253,16 +256,8 @@ fs = *fsp; if (fs->fs_magic == FS_BAD_MAGIC) return (EINVAL); - if (!(((fs->fs_magic == FS_UFS1_MAGIC && (isaltsblk || - sblockloc <= SBLOCK_UFS1)) || - (fs->fs_magic == FS_UFS2_MAGIC && (isaltsblk || - sblockloc == fs->fs_sblockloc))) && - fs->fs_ncg >= 1 && - fs->fs_bsize >= MINBSIZE && - fs->fs_bsize <= MAXBSIZE && - fs->fs_bsize >= roundup(sizeof(struct fs), DEV_BSIZE) && - fs->fs_sbsize <= SBLOCKSIZE)) - return (ENOENT); + if ((error = validate_sblock(fs, isaltsblk)) != 0) + return (error); /* * If the filesystem has been run on a kernel without * metadata check hashes, disable them. @@ -310,6 +305,144 @@ return (0); } +/* + * Two functions needed to verify the filesystem values. + */ +static int +ilog2(int val) +{ + u_int n; + + for (n = 0; n < sizeof(n) * CHAR_BIT; n++) + if (1 << n == val) + return (n); + return (-1); +} + +#define POWEROF2(num) (((num) & ((num) - 1)) == 0) + +/* + * Verify the filesystem values. + */ +static int +validate_sblock(struct fs *fs, int isaltsblk) +{ + int i, sectorsize; + u_int64_t maxfilesize, sizepb; + + sectorsize = dbtob(1); + if (fs->fs_magic == FS_UFS2_MAGIC) { + if ((!isaltsblk && (fs->fs_sblockloc != SBLOCK_UFS2 || + fs->fs_sblockactualloc != SBLOCK_UFS2)) || + fs->fs_maxsymlinklen != ((UFS_NDADDR + UFS_NIADDR) * + sizeof(ufs2_daddr_t)) || + fs->fs_nindir != fs->fs_bsize / sizeof(ufs2_daddr_t) || + fs->fs_inopb != fs->fs_bsize / sizeof(struct ufs2_dinode)) + return (ENOENT); + } else if (fs->fs_magic == FS_UFS1_MAGIC) { + if ((!isaltsblk && (fs->fs_sblockloc > SBLOCK_UFS1 || + fs->fs_sblockactualloc != SBLOCK_UFS1)) || + fs->fs_nindir != fs->fs_bsize / sizeof(ufs1_daddr_t) || + fs->fs_inopb != fs->fs_bsize / sizeof(struct ufs1_dinode) || + fs->fs_maxsymlinklen != ((UFS_NDADDR + UFS_NIADDR) * + sizeof(ufs1_daddr_t)) || + fs->fs_old_inodefmt != FS_44INODEFMT || + fs->fs_old_cgoffset != 0 || + fs->fs_old_cgmask != 0xffffffff || + fs->fs_old_size != fs->fs_size || + fs->fs_old_rotdelay != 0 || + fs->fs_old_rps != 60 || + fs->fs_old_nspf != fs->fs_fsize / sectorsize || + fs->fs_old_cpg != 1 || + fs->fs_old_interleave != 1 || + fs->fs_old_trackskew != 0 || + fs->fs_old_cpc != 0 || + fs->fs_old_postblformat != 1 || + fs->fs_old_nrpos != 1 || + fs->fs_old_spc != fs->fs_fpg * fs->fs_old_nspf || + fs->fs_old_nsect != fs->fs_old_spc || + fs->fs_old_npsect != fs->fs_old_spc || + fs->fs_old_dsize != fs->fs_dsize || + fs->fs_old_ncyl != fs->fs_ncg) + return (ENOENT); + } else { + return (ENOENT); + } + if (fs->fs_bsize < MINBSIZE || fs->fs_bsize > MAXBSIZE || + fs->fs_bsize < roundup(sizeof(struct fs), DEV_BSIZE) || + fs->fs_sbsize > SBLOCKSIZE || !POWEROF2(fs->fs_bsize)) + return (ENOENT); + if (fs->fs_fsize < sectorsize || fs->fs_fsize > fs->fs_bsize || + fs->fs_fsize * MAXFRAG < fs->fs_bsize || !POWEROF2(fs->fs_fsize)) + return (ENOENT); + if (fs->fs_maxbsize < fs->fs_bsize || !POWEROF2(fs->fs_maxbsize) || + fs->fs_maxbsize > FS_MAXCONTIG * fs->fs_bsize) + return (ENOENT); + if (fs->fs_bmask != ~(fs->fs_bsize - 1) || + fs->fs_fmask != ~(fs->fs_fsize - 1) || + fs->fs_qbmask != ~fs->fs_bmask || + fs->fs_qfmask != ~fs->fs_fmask || + fs->fs_bshift != ilog2(fs->fs_bsize) || + fs->fs_fshift != ilog2(fs->fs_fsize) || + fs->fs_frag != numfrags(fs, fs->fs_bsize) || + fs->fs_fragshift != ilog2(fs->fs_frag) || + fs->fs_frag > MAXFRAG || + fs->fs_fsbtodb != ilog2(fs->fs_fsize / sectorsize)) + return (ENOENT); + if (fs->fs_sblkno != + roundup(howmany(fs->fs_sblockloc + SBLOCKSIZE, fs->fs_fsize), + fs->fs_frag) || + fs->fs_cblkno != fs->fs_sblkno + + roundup(howmany(SBLOCKSIZE, fs->fs_fsize), fs->fs_frag) || + fs->fs_iblkno != fs->fs_cblkno + fs->fs_frag || + fs->fs_dblkno != fs->fs_iblkno + fs->fs_ipg / INOPF(fs) || + fs->fs_cgsize != fragroundup(fs, CGSIZE(fs))) + return (ENOENT); + if (fs->fs_csaddr != cgdmin(fs, 0) || + fs->fs_cssize != + fragroundup(fs, fs->fs_ncg * sizeof(struct csum)) || + fs->fs_dsize != fs->fs_size - fs->fs_sblkno - + fs->fs_ncg * (fs->fs_dblkno - fs->fs_sblkno) - + howmany(fs->fs_cssize, fs->fs_fsize) || + fs->fs_metaspace < 0 || fs->fs_metaspace > fs->fs_fpg / 2 || + fs->fs_minfree > 99) + return (ENOENT); + maxfilesize = fs->fs_bsize * UFS_NDADDR - 1; + for (sizepb = fs->fs_bsize, i = 0; i < UFS_NIADDR; i++) { + sizepb *= NINDIR(fs); + maxfilesize += sizepb; + } + if (fs->fs_maxfilesize != maxfilesize) + return (ENOENT); + /* + * These values have a tight interaction with each other that + * makes it hard to tightly bound them. So we can only check + * that they are within a broader possible range. + */ + if (fs->fs_ncg < 1 || fs->fs_ncg > fs->fs_size / 4 * fs->fs_frag || + fs->fs_fpg < 4 * fs->fs_frag || fs->fs_fpg > fs->fs_size || + fs->fs_ipg < NINDIR(fs) || fs->fs_ipg > fs->fs_fpg || + fs->fs_ipg * fs->fs_ncg > (((int64_t)(1)) << 32) - INOPB(fs) || + fs->fs_size < 4 * fs->fs_frag) + return (ENOENT); + if (fs->fs_size <= (fs->fs_ncg - 1) * fs->fs_fpg || + fs->fs_size > fs->fs_ncg * fs->fs_fpg) + return (ENOENT); + /* + * Maxcontig sets the default for the maximum number of blocks + * that may be allocated sequentially. With file system clustering + * it is possible to allocate contiguous blocks up to the maximum + * transfer size permitted by the controller or buffering. + */ + if (fs->fs_maxcontig < 1 || + fs->fs_maxcontig > MAX(1, maxphys / fs->fs_bsize)) + return (ENOENT); + if (fs->fs_maxcontig > 1 && + fs->fs_contigsumsize != MIN(fs->fs_maxcontig, FS_MAXCONTIG)) + return (ENOENT); + return (0); +} + /* * Write a superblock to the devfd device from the memory pointed to by fs. * Write out the superblock summary information if it is present.