Module Name: src Committed By: msaitoh Date: Sun Nov 9 06:38:55 UTC 2014
Modified Files: src/sys/fs/msdosfs [netbsd-6-1]: msdosfs_vfsops.c Log Message: Pull up following revision(s) (requested by maxv in ticket #1171): sys/fs/msdosfs/msdosfs_vfsops.c: revision 1.110 via patch - From me, FreeBSD, OpenBSD and the FAT specification. Ok christos@ - Perform sanity checks not just for GEMDOSFS, but for all FAT devices. This also fixes a division-by-zero bug that could crash the system. - Define GEMDOSFS_BSIZE instead of a hard-coded 512 value, and remove 'bsize'. - Rename 'tmp' to 'BlkPerSec'. - Remove 'secsize==0' and added 'secsize<DEV_BSIZE' To generate a diff of this commit: cvs rdiff -u -r1.93.6.1.6.1 -r1.93.6.1.6.2 \ src/sys/fs/msdosfs/msdosfs_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/fs/msdosfs/msdosfs_vfsops.c diff -u src/sys/fs/msdosfs/msdosfs_vfsops.c:1.93.6.1.6.1 src/sys/fs/msdosfs/msdosfs_vfsops.c:1.93.6.1.6.2 --- src/sys/fs/msdosfs/msdosfs_vfsops.c:1.93.6.1.6.1 Mon Apr 21 10:17:48 2014 +++ src/sys/fs/msdosfs/msdosfs_vfsops.c Sun Nov 9 06:38:55 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: msdosfs_vfsops.c,v 1.93.6.1.6.1 2014/04/21 10:17:48 bouyer Exp $ */ +/* $NetBSD: msdosfs_vfsops.c,v 1.93.6.1.6.2 2014/11/09 06:38:55 msaitoh Exp $ */ /*- * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. @@ -48,7 +48,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.93.6.1.6.1 2014/04/21 10:17:48 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.93.6.1.6.2 2014/11/09 06:38:55 msaitoh Exp $"); #if defined(_KERNEL_OPT) #include "opt_compat_netbsd.h" @@ -93,6 +93,8 @@ MODULE(MODULE_CLASS_VFS, msdos, NULL); #define DPRINTF(a) #endif +#define GEMDOSFS_BSIZE 512 + #define MSDOSFS_NAMEMAX(pmp) \ (pmp)->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12 @@ -474,8 +476,7 @@ msdosfs_mountfs(struct vnode *devvp, str struct byte_bpb50 *b50; struct byte_bpb710 *b710; uint8_t SecPerClust; - int ronly, error, tmp; - int bsize; + int ronly, error, BlkPerSec; uint64_t psize; unsigned secsize; @@ -493,7 +494,7 @@ msdosfs_mountfs(struct vnode *devvp, str goto error_exit; error = getdisksize(devvp, &psize, &secsize); - if (error || secsize == 0) { + if (error) { if (argp->flags & MSDOSFSMNT_GEMDOSFS) goto error_exit; @@ -502,16 +503,19 @@ msdosfs_mountfs(struct vnode *devvp, str psize = 0; error = 0; } + if (secsize < DEV_BSIZE) { + DPRINTF(("Invalid block secsize (%d < DEV_BSIZE)", secsize)); + error = EINVAL; + goto error_exit; + } if (argp->flags & MSDOSFSMNT_GEMDOSFS) { - bsize = secsize; - if (bsize != 512) { - DPRINTF(("Invalid block bsize %d for gemdos\n", bsize)); + if (secsize != GEMDOSFS_BSIZE) { + DPRINTF(("Invalid block secsize %d for GEMDOS\n", secsize)); error = EINVAL; goto error_exit; } - } else - bsize = 0; + } /* * Read the boot sector of the filesystem, and then check the @@ -555,19 +559,6 @@ msdosfs_mountfs(struct vnode *devvp, str pmp->pm_Heads = getushort(b50->bpbHeads); pmp->pm_Media = b50->bpbMedia; - if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { - /* XXX - We should probably check more values here */ - if (!pmp->pm_BytesPerSec || !SecPerClust - || pmp->pm_SecPerTrack > 63) { - DPRINTF(("bytespersec %d secperclust %d " - "secpertrack %d\n", - pmp->pm_BytesPerSec, SecPerClust, - pmp->pm_SecPerTrack)); - error = EINVAL; - goto error_exit; - } - } - if (pmp->pm_Sectors == 0) { pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); @@ -576,6 +567,29 @@ msdosfs_mountfs(struct vnode *devvp, str pmp->pm_HugeSectors = pmp->pm_Sectors; } + /* + * Sanity checks, from the FAT specification: + * - sectors per cluster: >= 1, power of 2 + * - logical sector size: >= 1, power of 2 + * - cluster size: <= max FS block size + * - number of sectors: >= 1 + */ + if ((SecPerClust == 0) || !powerof2(SecPerClust) || + (pmp->pm_BytesPerSec == 0) || !powerof2(pmp->pm_BytesPerSec) || + (SecPerClust * pmp->pm_BytesPerSec > MAXBSIZE) || + (pmp->pm_HugeSectors == 0)) { + DPRINTF(("consistency checks\n")); + error = EINVAL; + goto error_exit; + } + + if (!(argp->flags & MSDOSFSMNT_GEMDOSFS) && + (pmp->pm_SecPerTrack > 63)) { + DPRINTF(("SecPerTrack %d\n", pmp->pm_SecPerTrack)); + error = EINVAL; + goto error_exit; + } + if (pmp->pm_RootDirEnts == 0) { unsigned short vers = getushort(b710->bpbFSVers); /* @@ -614,17 +628,12 @@ msdosfs_mountfs(struct vnode *devvp, str /* * Check a few values (could do some more): - * - logical sector size: power of 2, >= block size - * - sectors per cluster: power of 2, >= 1 - * - number of sectors: >= 1, <= size of partition + * - logical sector size: >= block size + * - number of sectors: <= size of partition */ - if ( (SecPerClust == 0) - || (SecPerClust & (SecPerClust - 1)) - || (pmp->pm_BytesPerSec < bsize) - || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) - || (pmp->pm_HugeSectors == 0) - || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize) - > psize)) { + if ((pmp->pm_BytesPerSec < GEMDOSFS_BSIZE) || + (pmp->pm_HugeSectors * + (pmp->pm_BytesPerSec / GEMDOSFS_BSIZE) > psize)) { DPRINTF(("consistency checks for gemdos\n")); error = EINVAL; goto error_exit; @@ -635,14 +644,14 @@ msdosfs_mountfs(struct vnode *devvp, str * always be the same as the number of bytes per disk block * Let's pretend it is. */ - tmp = pmp->pm_BytesPerSec / bsize; - pmp->pm_BytesPerSec = bsize; - pmp->pm_HugeSectors *= tmp; - pmp->pm_HiddenSects *= tmp; - pmp->pm_ResSectors *= tmp; - pmp->pm_Sectors *= tmp; - pmp->pm_FATsecs *= tmp; - SecPerClust *= tmp; + BlkPerSec = pmp->pm_BytesPerSec / GEMDOSFS_BSIZE; + pmp->pm_BytesPerSec = GEMDOSFS_BSIZE; + pmp->pm_HugeSectors *= BlkPerSec; + pmp->pm_HiddenSects *= BlkPerSec; + pmp->pm_ResSectors *= BlkPerSec; + pmp->pm_Sectors *= BlkPerSec; + pmp->pm_FATsecs *= BlkPerSec; + SecPerClust *= BlkPerSec; } /* Check that fs has nonzero FAT size */