Date: Wed, 23 Sep 2020 06:52:23 +0000 (UTC) From: Xin LI <delphij@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r366064 - head/sbin/fsck_msdosfs Message-ID: <202009230652.08N6qNsa070062@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: delphij Date: Wed Sep 23 06:52:22 2020 New Revision: 366064 URL: https://svnweb.freebsd.org/changeset/base/366064 Log: sbin/fsck_msdosfs: Fix an integer overflow on 32-bit platforms. The purpose of checksize() is to verify that the referenced cluster chain size matches the recorded file size (up to 2^32 - 1) in the directory entry. We follow the cluster chain, then multiple the cluster count by bytes per cluster to get the physical size, then check it against the recorded size. When a file is close to 4 GiB (between 4GiB - cluster size and 4GiB, both non-inclusive), the product of cluster count and bytes per cluster would be exactly 4 GiB. On 32-bit systems, because size_t is 32-bit, this would wrap back to 0, which will cause the file be truncated to 0. Fix this by using 64-bit physicalSize instead. This fix is inspired by an Android change request at https://android-review.googlesource.com/c/platform/external/fsck_msdos/+/1428461 PR: 249533 Reviewed by: kevlo MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D26524 Modified: head/sbin/fsck_msdosfs/dir.c Modified: head/sbin/fsck_msdosfs/dir.c ============================================================================== --- head/sbin/fsck_msdosfs/dir.c Wed Sep 23 04:09:02 2020 (r366063) +++ head/sbin/fsck_msdosfs/dir.c Wed Sep 23 06:52:22 2020 (r366064) @@ -388,7 +388,8 @@ static int checksize(struct fat_descriptor *fat, u_char *p, struct dosDirEntry *dir) { int ret = FSOK; - size_t physicalSize; + size_t chainsize; + u_int64_t physicalSize; struct bootblock *boot; boot = fat_get_boot(fat); @@ -401,9 +402,9 @@ checksize(struct fat_descriptor *fat, u_char *p, struc } else { if (!fat_is_valid_cl(fat, dir->head)) return FSERROR; - ret = checkchain(fat, dir->head, &physicalSize); + ret = checkchain(fat, dir->head, &chainsize); /* - * Upon return, physicalSize would hold the chain length + * Upon return, chainsize would hold the chain length * that checkchain() was able to validate, but if the user * refused the proposed repair, it would be unsafe to * proceed with directory entry fix, so bail out in that @@ -412,7 +413,13 @@ checksize(struct fat_descriptor *fat, u_char *p, struc if (ret == FSERROR) { return (FSERROR); } - physicalSize *= boot->ClusterSize; + /* + * The maximum file size on FAT32 is 4GiB - 1, which + * will occupy a cluster chain of exactly 4GiB in + * size. On 32-bit platforms, since size_t is 32-bit, + * it would wrap back to 0. + */ + physicalSize = (u_int64_t)chainsize * boot->ClusterSize; } if (physicalSize < dir->size) { pwarn("size of %s is %u, should at most be %zu\n",
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202009230652.08N6qNsa070062>