diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-02-13 15:56:23 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-02-13 15:56:23 +0000 |
commit | bc03fb770949a9e8cc10603a444e4e6692714422 (patch) | |
tree | 25ca4c38277fac9cf04879a4a406c1c0c1841d80 | |
parent | ba5404b04a7998141d8413802f2ab7e781498829 (diff) |
Do some extra validation of the superblock, otherwise a corrupt
superblock might lead to crashes or other mishap. Now my fuzzed fs
images no longer crash fsck_ffs. ok mickey@ pedro@ millert@
-rw-r--r-- | sbin/fsck_ffs/setup.c | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c index 85643ddf382..44cfcafcb69 100644 --- a/sbin/fsck_ffs/setup.c +++ b/sbin/fsck_ffs/setup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: setup.c,v 1.27 2007/02/12 16:32:54 otto Exp $ */ +/* $OpenBSD: setup.c,v 1.28 2007/02/13 15:56:22 otto Exp $ */ /* $NetBSD: setup.c,v 1.27 1996/09/27 22:45:19 christos Exp $ */ /* @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)setup.c 8.5 (Berkeley) 11/23/94"; #else -static const char rcsid[] = "$OpenBSD: setup.c,v 1.27 2007/02/12 16:32:54 otto Exp $"; +static const char rcsid[] = "$OpenBSD: setup.c,v 1.28 2007/02/13 15:56:22 otto Exp $"; #endif #endif /* not lint */ @@ -227,6 +227,26 @@ setup(char *dev) dirty(&asblk); } } + if (1 << sblock.fs_bshift != sblock.fs_bsize) { + pwarn("INCORRECT BSHIFT=%d IN SUPERBLOCK", sblock.fs_bshift); + sblock.fs_bshift = ffs(sblock.fs_bsize) - 1; + if (preen) + printf(" (FIXED)\n"); + if (preen || reply("FIX") == 1) { + sbdirty(); + dirty(&asblk); + } + } + if (1 << sblock.fs_fshift != sblock.fs_fsize) { + pwarn("INCORRECT FSHIFT=%d IN SUPERBLOCK", sblock.fs_fshift); + sblock.fs_fshift = ffs(sblock.fs_fsize) - 1; + if (preen) + printf(" (FIXED)\n"); + if (preen || reply("FIX") == 1) { + sbdirty(); + dirty(&asblk); + } + } if (sblock.fs_inodefmt >= FS_44INODEFMT) { if (sblock.fs_maxfilesize != maxfilesize) { pwarn("INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK", @@ -316,6 +336,36 @@ setup(char *dev) sbdirty(); dirty(&asblk); } + if (sblock.fs_cgsize != fragroundup(&sblock, CGSIZE(&sblock))) { + pwarn("INCONSISTENT CGSIZE=%d\n", sblock.fs_cgsize); + sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); + if (preen) + printf(" (FIXED)\n"); + if (preen || reply("FIX") == 1) { + sbdirty(); + dirty(&asblk); + } + } + if (INOPB(&sblock) != sblock.fs_bsize / sizeof(struct ufs1_dinode)) { + pwarn("INCONSISTENT INOPB=%d\n", INOPB(&sblock)); + sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); + if (preen) + printf(" (FIXED)\n"); + if (preen || reply("FIX") == 1) { + sbdirty(); + dirty(&asblk); + } + } + if (NINDIR(&sblock) != sblock.fs_bsize / sizeof(ufs1_daddr_t)) { + pwarn("INCONSISTENT NINDIR=%d\n", NINDIR(&sblock)); + sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t); + if (preen) + printf(" (FIXED)\n"); + if (preen || reply("FIX") == 1) { + sbdirty(); + dirty(&asblk); + } + } if (asblk.b_dirty && !bflag) { memcpy(&altsblock, &sblock, (size_t)sblock.fs_sbsize); flush(fswritefd, &asblk); @@ -427,10 +477,19 @@ readsb(int listerr) return (0); } if (sblock.fs_sbsize > SBSIZE) { - badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); + badsb(listerr, "SBSIZE PREPOSTEROUSLY LARGE"); return (0); } + if (!POWEROF2(sblock.fs_bsize) || sblock.fs_bsize < MINBSIZE || + sblock.fs_bsize > MAXBSIZE) + badsb(listerr, "ILLEGAL BLOCK SIZE"); + + if (!POWEROF2(sblock.fs_fsize) || sblock.fs_fsize > sblock.fs_bsize || + sblock.fs_fsize < sblock.fs_bsize / MAXFRAG) + badsb(listerr, "ILLEGAL FRAGMENT SIZE"); + + /* * Compute block size that the filesystem is based on, * according to fsbtodb, and adjust superblock block number |