Module Name: src Committed By: mlelstv Date: Sun Aug 20 11:48:15 UTC 2017
Modified Files: src/sys/fs/msdosfs: msdosfs_vfsops.c Log Message: Add more sanity checks for BPB parameters. Handle FAT12 format for media with sectors >= 32kByte. Does fix PR 52485. To generate a diff of this commit: cvs rdiff -u -r1.127 -r1.128 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.127 src/sys/fs/msdosfs/msdosfs_vfsops.c:1.128 --- src/sys/fs/msdosfs/msdosfs_vfsops.c:1.127 Mon Apr 17 08:32:00 2017 +++ src/sys/fs/msdosfs/msdosfs_vfsops.c Sun Aug 20 11:48:15 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: msdosfs_vfsops.c,v 1.127 2017/04/17 08:32:00 hannken Exp $ */ +/* $NetBSD: msdosfs_vfsops.c,v 1.128 2017/08/20 11:48:15 mlelstv 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.127 2017/04/17 08:32:00 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.128 2017/08/20 11:48:15 mlelstv Exp $"); #if defined(_KERNEL_OPT) #include "opt_compat_netbsd.h" @@ -467,6 +467,7 @@ msdosfs_mountfs(struct vnode *devvp, str int ronly, error, BlkPerSec; uint64_t psize; unsigned secsize; + u_long fatbytes, fatblocksecs; /* Flush out any old buffers remaining from a previous use. */ if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0) @@ -710,12 +711,40 @@ msdosfs_mountfs(struct vnode *devvp, str pmp->pm_fatdiv = 1; } } - if (FAT12(pmp)) - pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; - else + + /* validate cluster count against FAT */ + if ((pmp->pm_maxcluster & pmp->pm_fatmask) != pmp->pm_maxcluster) { + DPRINTF("maxcluster %lu outside of mask %#lx\n", + pmp->pm_maxcluster, pmp->pm_fatmask); + error = EINVAL; + goto error_exit; + } + + /* validate FAT size */ + fatbytes = (pmp->pm_maxcluster+1) * pmp->pm_fatmult / pmp->pm_fatdiv; + fatblocksecs = howmany(fatbytes, pmp->pm_BytesPerSec); + + if (pmp->pm_FATsecs != fatblocksecs) { + DPRINTF("FATsecs %lu != real %lu\n", pmp->pm_FATsecs, + fatblocksecs); + error = EINVAL; + goto error_exit; + } + + if (FAT12(pmp)) { + /* + * limit block size to what is needed to read a FAT block + * to not exceed MAXBSIZE + */ + pmp->pm_fatblocksec = min(3, fatblocksecs); + pmp->pm_fatblocksize = pmp->pm_fatblocksec + * pmp->pm_BytesPerSec; + } else { pmp->pm_fatblocksize = MAXBSIZE; + pmp->pm_fatblocksec = pmp->pm_fatblocksize + / pmp->pm_BytesPerSec; + } - pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; /*