Page MenuHomeFreeBSD

D35219.id106252.diff
No OneTemporary

D35219.id106252.diff

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 <sys/param.h>
+#include <sys/limits.h>
#ifndef _KERNEL
#include <stdio.h>
@@ -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 <sys/systm.h>
@@ -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.
@@ -141,7 +144,7 @@
* EIO: non-existent or truncated superblock.
* EIO: error reading summary information.
* ENOENT: no usable known superblock found.
- * ENOSPC: failed to allocate space for the superblock.
+ * ENOMEM: failed to allocate space for the superblock.
* EINVAL: The previous newfs operation on this volume did not complete.
* The administrator must complete newfs before using this volume.
*/
@@ -152,7 +155,8 @@
{
struct fs *fs;
struct fs_summary_info *fs_si;
- int i, error, size, blks;
+ int i, error;
+ uint64_t size, blks;
uint8_t *space;
int32_t *lp;
char *buf;
@@ -190,17 +194,16 @@
if (fs->fs_contigsumsize > 0)
size += fs->fs_ncg * sizeof(int32_t);
size += fs->fs_ncg * sizeof(u_int8_t);
- /* When running in libufs or libsa, UFS_MALLOC may fail */
- if ((fs_si = UFS_MALLOC(sizeof(*fs_si), filltype, M_WAITOK)) == NULL) {
+ if ((fs_si = UFS_MALLOC(sizeof(*fs_si), filltype, M_NOWAIT)) == NULL) {
UFS_FREE(fs, filltype);
- return (ENOSPC);
+ return (ENOMEM);
}
bzero(fs_si, sizeof(*fs_si));
fs->fs_si = fs_si;
- if ((space = UFS_MALLOC(size, filltype, M_WAITOK)) == NULL) {
+ if ((space = UFS_MALLOC(size, filltype, M_NOWAIT)) == NULL) {
UFS_FREE(fs->fs_si, filltype);
UFS_FREE(fs, filltype);
- return (ENOSPC);
+ return (ENOMEM);
}
fs->fs_csp = (struct csum *)space;
for (i = 0; i < blks; i += fs->fs_frag) {
@@ -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,134 @@
return (0);
}
+/*
+ * Verify the filesystem values.
+ */
+#define ILOG2(num) (fls(num) - 1)
+#define MINFPG 18928
+
+static int
+validate_sblock(struct fs *fs, int isaltsblk)
+{
+ int i, sectorsize;
+ u_int64_t maxfilesize, minfpg, 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 || fs->fs_sbsize < fs->fs_fsize ||
+ !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.
+ */
+ minfpg = MIN(fs->fs_size / 4, MINFPG);
+ if (fs->fs_ncg < 1 || fs->fs_ncg > (fs->fs_size / minfpg) + 1 ||
+ fs->fs_fpg < minfpg || fs->fs_fpg > fs->fs_size ||
+ fs->fs_ipg * fs->fs_ncg > (((int64_t)(1)) << 32) - INOPB(fs) ||
+ fs->fs_ipg > fs->fs_fpg || fs->fs_size < 8 * 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 < 0 ||
+ (fs->fs_maxcontig == 0 && fs->fs_contigsumsize != 0) ||
+ (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.

File Metadata

Mime Type
text/plain
Expires
Mon, Sep 23, 11:21 PM (3 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
12601089
Default Alt Text
D35219.id106252.diff (7 KB)

Event Timeline