diff options
author | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2001-04-13 02:39:07 +0000 |
---|---|---|
committer | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2001-04-13 02:39:07 +0000 |
commit | 9bff9fb87213262bc5d1afd9333ad540d9e99c54 (patch) | |
tree | 5797ca5b1e346d54d4606ff7293258862d4b223b /sys/ufs/ffs/ffs_vfsops.c | |
parent | 5af2b89b71f9bb495e071539ea9548813c712c7c (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/ufs/ffs/ffs_vfsops.c')
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 25 |
1 files changed, 13 insertions, 12 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) |