Module Name:    src
Committed By:   maxv
Date:           Sat Feb 14 09:55:53 UTC 2015

Modified Files:
        src/sys/ufs/ffs: ffs_vfsops.c

Log Message:
In fact, we need to sanitize the superblock *after* swapping it. Therefore,
move the swap code inside the loop.

'fs->fs_sbsize' is swapped twice: the first time in order to get the
correct superblock size, and later when swapping the whole superblock
structure. As a result, we need to check 'fs->fs_sbsize' twice.

This:
 - fixes my previous changes for swapped FSes
 - allows the kernel to look for other superblock locations if the
   current superblock is not validated

And now:
 - ffs_superblock_validate() takes only one argument: the fs structure
 - 'fs_bsize' is unused, so delete it

Add some comments to explain a bit what we are doing.


To generate a diff of this commit:
cvs rdiff -u -r1.313 -r1.314 src/sys/ufs/ffs/ffs_vfsops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/ufs/ffs/ffs_vfsops.c
diff -u src/sys/ufs/ffs/ffs_vfsops.c:1.313 src/sys/ufs/ffs/ffs_vfsops.c:1.314
--- src/sys/ufs/ffs/ffs_vfsops.c:1.313	Sat Feb 14 09:00:12 2015
+++ src/sys/ufs/ffs/ffs_vfsops.c	Sat Feb 14 09:55:53 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_vfsops.c,v 1.313 2015/02/14 09:00:12 maxv Exp $	*/
+/*	$NetBSD: ffs_vfsops.c,v 1.314 2015/02/14 09:55:53 maxv Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.313 2015/02/14 09:00:12 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.314 2015/02/14 09:55:53 maxv Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -115,7 +115,7 @@ static int
 ffs_vfs_fsync(vnode_t *, int);
 
 static int
-ffs_superblock_validate(struct fs *fs, u_int32_t fs_sbsize, int32_t fs_bsize);
+ffs_superblock_validate(struct fs *fs);
 
 static struct sysctllog *ffs_sysctl_log;
 
@@ -758,7 +758,7 @@ ffs_reload(struct mount *mp, kauth_cred_
 		kmem_free(newfs, fs_sbsize);
 		return (EIO);		/* XXX needs translation */
 	}
-	if (!ffs_superblock_validate(newfs, newfs->fs_sbsize, newfs->fs_bsize)) {
+	if (!ffs_superblock_validate(newfs)) {
 		brelse(bp, 0);
 		kmem_free(newfs, fs_sbsize);
 		return (EINVAL);
@@ -923,16 +923,16 @@ static const int sblock_try[] = SBLOCKSE
 
 
 static int
-ffs_superblock_validate(struct fs *fs, u_int32_t fs_sbsize, int32_t fs_bsize)
+ffs_superblock_validate(struct fs *fs)
 {
 	/* Check the superblock size */
-	if (fs_sbsize > SBLOCKSIZE || fs_sbsize < sizeof(struct fs))
+	if (fs->fs_sbsize > SBLOCKSIZE || fs->fs_sbsize < sizeof(struct fs))
 		return 0;
 
 	/* Check the file system blocksize */
-	if (fs_bsize > MAXBSIZE || fs_bsize < MINBSIZE)
+	if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < MINBSIZE)
 		return 0;
-	if (!powerof2(fs_bsize))
+	if (!powerof2(fs->fs_bsize))
 		return 0;
 
 	/* Check the size of frag blocks */
@@ -945,11 +945,11 @@ ffs_superblock_validate(struct fs *fs, u
 		return 0;
 
 	/* Block size cannot be smaller than fragment size */
-	if (fs_bsize < fs->fs_fsize)
+	if (fs->fs_bsize < fs->fs_fsize)
 		return 0;
 
 	/* Check the number of frag blocks */
-	if ((fs_bsize / fs->fs_fsize) > MAXFRAG)
+	if ((fs->fs_bsize / fs->fs_fsize) > MAXFRAG)
 		return 0;
 
 	return 1;
@@ -1015,7 +1015,6 @@ ffs_mountfs(struct vnode *devvp, struct 
 	 */
 	for (i = 0; ; i++) {
 		daddr_t fsblockloc;
-		int32_t fs_bsize;
 
 		if (bp != NULL) {
 			brelse(bp, BC_NOCACHE);
@@ -1040,28 +1039,30 @@ ffs_mountfs(struct vnode *devvp, struct 
 
 		fsblockloc = sblockloc = sblock_try[i];
 		DPRINTF(("%s: fs_magic 0x%x\n", __func__, fs->fs_magic));
+
+		/*
+		 * Swap: here, we swap fs->fs_sbsize in order to get the correct
+		 * size to read the superblock. Once read, we swap the whole
+		 * superblock structure.
+		 */
 		if (fs->fs_magic == FS_UFS1_MAGIC) {
 			fs_sbsize = fs->fs_sbsize;
 			fstype = UFS1;
-			fs_bsize = fs->fs_bsize;
 #ifdef FFS_EI
 			needswap = 0;
 		} else if (fs->fs_magic == FS_UFS1_MAGIC_SWAPPED) {
 			fs_sbsize = bswap32(fs->fs_sbsize);
 			fstype = UFS1;
-			fs_bsize = bswap32(fs->fs_bsize);
 			needswap = 1;
 #endif
 		} else if (fs->fs_magic == FS_UFS2_MAGIC) {
 			fs_sbsize = fs->fs_sbsize;
 			fstype = UFS2;
-			fs_bsize = fs->fs_bsize;
 #ifdef FFS_EI
 			needswap = 0;
 		} else if (fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) {
 			fs_sbsize = bswap32(fs->fs_sbsize);
 			fstype = UFS2;
-			fs_bsize = bswap32(fs->fs_bsize);
 			needswap = 1;
 #endif
 		} else
@@ -1089,25 +1090,36 @@ ffs_mountfs(struct vnode *devvp, struct 
 		if (fsblockloc != sblockloc)
 			continue;
 
-		if (!ffs_superblock_validate(fs, fs_sbsize, fs_bsize))
+		/* Check the superblock size */
+		if (fs_sbsize > SBLOCKSIZE || fs_sbsize < sizeof(struct fs))
 			continue;
+		fs = kmem_alloc((u_long)fs_sbsize, KM_SLEEP);
+		memcpy(fs, bp->b_data, fs_sbsize);
+
+		/* Swap the whole superblock structure, if necessary. */
+#ifdef FFS_EI
+		if (needswap) {
+			ffs_sb_swap((struct fs*)bp->b_data, fs);
+			fs->fs_flags |= FS_SWAPPED;
+		} else
+#endif
+			fs->fs_flags &= ~FS_SWAPPED;
+
+		/*
+		 * Now that everything is swapped, the superblock is ready to
+		 * be sanitized.
+		 */
+		if (!ffs_superblock_validate(fs)) {
+			kmem_free(fs, fs_sbsize);
+			continue;
+		}
 
 		/* Ok seems to be a good superblock */
 		break;
 	}
 
-	fs = kmem_alloc((u_long)fs_sbsize, KM_SLEEP);
-	memcpy(fs, bp->b_data, fs_sbsize);
 	ump->um_fs = fs;
 
-#ifdef FFS_EI
-	if (needswap) {
-		ffs_sb_swap((struct fs*)bp->b_data, fs);
-		fs->fs_flags |= FS_SWAPPED;
-	} else
-#endif
-		fs->fs_flags &= ~FS_SWAPPED;
-
 #ifdef WAPBL
 	if ((mp->mnt_wapbl_replay == 0) && (fs->fs_flags & FS_DOWAPBL)) {
 		error = ffs_wapbl_replay_start(mp, fs, devvp);

Reply via email to