Module Name:    src
Committed By:   mlelstv
Date:           Tue May  3 18:17:29 UTC 2016

Modified Files:
        src/sys/fs/msdosfs: msdosfs_fat.c

Log Message:
Validate FAT entries to avoid some panics caused by a corrupted FAT.

Also print FAT write errors when mount is synchronous (-o sync). This
reveals problems caused by a write protected disklabel on sector 1.


To generate a diff of this commit:
cvs rdiff -u -r1.29 -r1.30 src/sys/fs/msdosfs/msdosfs_fat.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/fs/msdosfs/msdosfs_fat.c
diff -u src/sys/fs/msdosfs/msdosfs_fat.c:1.29 src/sys/fs/msdosfs/msdosfs_fat.c:1.30
--- src/sys/fs/msdosfs/msdosfs_fat.c:1.29	Sat Mar 28 19:24:05 2015
+++ src/sys/fs/msdosfs/msdosfs_fat.c	Tue May  3 18:17:28 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfs_fat.c,v 1.29 2015/03/28 19:24:05 maxv Exp $	*/
+/*	$NetBSD: msdosfs_fat.c,v 1.30 2016/05/03 18:17:28 mlelstv Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -52,7 +52,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msdosfs_fat.c,v 1.29 2015/03/28 19:24:05 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_fat.c,v 1.30 2016/05/03 18:17:28 mlelstv Exp $");
 
 /*
  * kernel include files.
@@ -273,6 +273,18 @@ pcbmap(struct denode *dep, u_long findcn
 		 */
 		if (cn >= (CLUST_RSRVD & pmp->pm_fatmask))
 			goto hiteof;
+
+		/*
+		 * Also stop when cluster is not in the filesystem
+		 */
+		if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster) {
+			DPRINTF(("%s(cn, %lu not in %lu..%lu)\n", __func__,
+				cn, CLUST_FIRST, pmp->pm_maxcluster));
+			if (bp)
+				brelse(bp, 0);
+			return (EINVAL);
+		}
+
 		byteoffset = FATOFS(pmp, cn);
 		fatblock(pmp, byteoffset, &bn, &bsize, &bo);
 		if (bn != bp_bn) {
@@ -383,7 +395,7 @@ fc_purge(struct denode *dep, u_int frcn)
 void
 updatefats(struct msdosfsmount *pmp, struct buf *bp, u_long fatbn)
 {
-	int i;
+	int i, error;
 	struct buf *bpn;
 
 	DPRINTF(("%s(pmp %p, bp %p, fatbn %lu)\n", __func__, pmp, bp, fatbn));
@@ -448,9 +460,12 @@ updatefats(struct msdosfsmount *pmp, str
 			bpn = getblk(pmp->pm_devvp, de_bn2kb(pmp, fatbn),
 			    bp->b_bcount, 0, 0);
 			memcpy(bpn->b_data, bp->b_data, bp->b_bcount);
-			if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
-				bwrite(bpn);
-			else
+			if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT) {
+				error = bwrite(bpn);
+				if (error)
+					printf("%s: copy FAT %d (error=%d)\n",
+						 __func__, i, error);
+			} else
 				bdwrite(bpn);
 		}
 	}
@@ -458,9 +473,12 @@ updatefats(struct msdosfsmount *pmp, str
 	/*
 	 * Write out the first (or current) FAT last.
 	 */
-	if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
-		bwrite(bp);
-	else
+	if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT) {
+		error =  bwrite(bp);
+		if (error)
+			printf("%s: write FAT (error=%d)\n",
+				__func__, error);
+	} else
 		bdwrite(bp);
 	/*
 	 * Maybe update fsinfo sector here?

Reply via email to