summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorGrigoriy Orlov <gluk@cvs.openbsd.org>2001-04-13 02:39:07 +0000
committerGrigoriy Orlov <gluk@cvs.openbsd.org>2001-04-13 02:39:07 +0000
commit9bff9fb87213262bc5d1afd9333ad540d9e99c54 (patch)
tree5797ca5b1e346d54d4606ff7293258862d4b223b /sys
parent5af2b89b71f9bb495e071539ea9548813c712c7c (diff)
Fix overflow in superblock. From FreeBSD.
FreeBSD's log: > The ffs superblock includes a 128-byte region for use by temporary > in-core pointers to summary information. An array in this region > (fs_csp) could overflow on filesystems with a very large number of > cylinder groups (~16000 on i386 with 8k blocks). When this happens, > other fields in the superblock get corrupted, and fsck refuses to > check the filesystem. > > Solve this problem by replacing the fs_csp array in 'struct fs' > with a single pointer, and add padding to keep the length of the > 128-byte region fixed. Update the kernel and userland utilities > to use just this single pointer. > > With this change, the kernel no longer makes use of the superblock > fields 'fs_csshift' and 'fs_csmask'. Add a comment to newfs/mkfs.c > to indicate that these fields must be calculated for compatibility > with older kernels. art@ ok.
Diffstat (limited to 'sys')
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c25
-rw-r--r--sys/ufs/ffs/fs.h38
2 files changed, 32 insertions, 31 deletions
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 10d31c10e67..3ffd6abf98e 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_vfsops.c,v 1.37 2001/04/12 17:16:52 csapuntz Exp $ */
+/* $OpenBSD: ffs_vfsops.c,v 1.38 2001/04/13 02:39:05 gluk Exp $ */
/* $NetBSD: ffs_vfsops.c,v 1.19 1996/02/09 22:22:26 christos Exp $ */
/*
@@ -446,7 +446,7 @@ ffs_reload(mountp, cred, p)
{
register struct vnode *vp, *nvp, *devvp;
struct inode *ip;
- struct csum *space;
+ caddr_t space;
struct buf *bp;
struct fs *fs, *newfs;
struct partinfo dpart;
@@ -487,7 +487,7 @@ ffs_reload(mountp, cred, p)
* new superblock. These should really be in the ufsmount. XXX
* Note that important parameters (eg fs_ncg) are unchanged.
*/
- bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp));
+ newfs->fs_csp = fs->fs_csp;
newfs->fs_maxcluster = fs->fs_maxcluster;
bcopy(newfs, fs, (u_int)fs->fs_sbsize);
if (fs->fs_sbsize < SBSIZE)
@@ -500,7 +500,7 @@ ffs_reload(mountp, cred, p)
* Step 3: re-read summary information from disk.
*/
blks = howmany(fs->fs_cssize, fs->fs_fsize);
- space = fs->fs_csp[0];
+ space = (caddr_t)fs->fs_csp;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
@@ -509,7 +509,8 @@ ffs_reload(mountp, cred, p)
NOCRED, &bp);
if (error)
return (error);
- bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
+ bcopy(bp->b_data, space, (u_int)size);
+ space += size;
brelse(bp);
}
if ((fs->fs_flags & FS_DOSOFTDEP))
@@ -582,7 +583,7 @@ ffs_mountfs(devvp, mp, p)
register struct fs *fs;
dev_t dev;
struct partinfo dpart;
- caddr_t base, space;
+ caddr_t space;
int error, i, blks, size, ronly;
int32_t *lp;
size_t strsize;
@@ -677,7 +678,8 @@ ffs_mountfs(devvp, mp, p)
blks = howmany(size, fs->fs_fsize);
if (fs->fs_contigsumsize > 0)
size += fs->fs_ncg * sizeof(int32_t);
- base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
+ space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
+ fs->fs_csp = (struct csum *)space;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
@@ -685,11 +687,10 @@ ffs_mountfs(devvp, mp, p)
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
cred, &bp);
if (error) {
- free(base, M_UFSMNT);
+ free(fs->fs_csp, M_UFSMNT);
goto out;
}
bcopy(bp->b_data, space, (u_int)size);
- fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
space += size;
brelse(bp);
bp = NULL;
@@ -754,7 +755,7 @@ ffs_mountfs(devvp, mp, p)
if (ronly == 0) {
if ((fs->fs_flags & FS_DOSOFTDEP) &&
(error = softdep_mount(devvp, mp, fs, cred)) != 0) {
- free(base, M_UFSMNT);
+ free(fs->fs_csp, M_UFSMNT);
free(fs->fs_contigdirs, M_UFSMNT);
goto out;
}
@@ -850,7 +851,7 @@ ffs_unmount(mp, mntflags, p)
error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
NOCRED, p);
vrele(ump->um_devvp);
- free(fs->fs_csp[0], M_UFSMNT);
+ free(fs->fs_csp, M_UFSMNT);
free(fs, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = (qaddr_t)0;
@@ -1235,7 +1236,7 @@ ffs_sbupdate(mp, waitfor)
* First write back the summary information.
*/
blks = howmany(fs->fs_cssize, fs->fs_fsize);
- space = (caddr_t)fs->fs_csp[0];
+ space = (caddr_t)fs->fs_csp;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h
index 3719eaba2df..e8e9f0bf3c1 100644
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fs.h,v 1.10 2001/04/07 17:25:38 millert Exp $ */
+/* $OpenBSD: fs.h,v 1.11 2001/04/13 02:39:04 gluk Exp $ */
/* $NetBSD: fs.h,v 1.6 1995/04/12 21:21:02 mycroft Exp $ */
/*
@@ -105,14 +105,19 @@
#define MAXMNTLEN 512
/*
- * The limit on the amount of summary information per file system
- * is defined by MAXCSBUFS. It is currently parameterized for a
- * size of 128 bytes (2 million cylinder groups on machines with
- * 32-bit pointers, and 1 million on 64-bit machines). One pointer
- * is taken away to point to an array of cluster sizes that is
- * computed as cylinder groups are inspected.
+ * There is a 128-byte region in the superblock reserved for in-core
+ * pointers to summary information. Originally this included an array
+ * of pointers to blocks of struct csum; now there are just three
+ * pointers and the remaining space is padded with fs_ocsp[].
+ *
+ * NOCSPTRS determines the size of this padding. One pointer (fs_csp)
+ * is taken away to point to a contiguous array of struct csum for
+ * all cylinder groups; a second (fs_maxcluster) points to an array
+ * of cluster sizes that is computed as cylinder groups are inspected,
+ * and the third points to an array that tracks the creation of new
+ * directories.
*/
-#define MAXCSBUFS ((128 / sizeof(void *)) - 1)
+#define NOCSPTRS ((128 / sizeof(void *)) - 2)
/*
* A summary of contiguous blocks of various sizes is maintained
@@ -142,9 +147,6 @@
* from first cylinder group data blocks. These blocks have to be
* read in from fs_csaddr (size fs_cssize) in addition to the
* super block.
- *
- * N.B. sizeof(struct csum) must be a power of two in order for
- * the ``fs_cs'' macro to work (see below).
*/
struct csum {
int32_t cs_ndir; /* number of directories */
@@ -188,8 +190,8 @@ struct fs {
int32_t fs_fragshift; /* block to frag shift */
int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t fs_sbsize; /* actual size of super block */
- int32_t fs_csmask; /* csum block offset */
- int32_t fs_csshift; /* csum block number */
+ int32_t fs_csmask; /* csum block offset (now unused) */
+ int32_t fs_csshift; /* csum block number (now unused) */
int32_t fs_nindir; /* value of NINDIR */
int32_t fs_inopb; /* value of INOPB */
int32_t fs_nspf; /* value of NSPF */
@@ -225,8 +227,9 @@ struct fs {
u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
/* these fields retain the current block allocation info */
int32_t fs_cgrotor; /* last cg searched */
- struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */
- int32_t *fs_maxcluster; /* max cluster in each cyl group */
+ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
+ struct csum *fs_csp; /* cg summary info buffer for fs_cs */
+ int32_t *fs_maxcluster; /* max cluster in each cyl group */
int32_t fs_cpc; /* cyl per cycle in postbl */
int16_t fs_opostbl[16][8]; /* old rotation block list head */
#if LONG_BIT == 64
@@ -317,11 +320,8 @@ struct fs {
/*
* Convert cylinder group to base address of its global summary info.
- *
- * N.B. This macro assumes that sizeof(struct csum) is a power of two.
*/
-#define fs_cs(fs, indx) \
- fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask]
+#define fs_cs(fs, indx) fs_csp[indx]
/*
* Cylinder group block for a file system.