summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-09-23 00:34:32 -0700
committerXin Li <delphij@google.com>2020-09-23 00:34:32 -0700
commit482403793438098b8e613ebb24bb6ae1046aeef3 (patch)
tree2f42e0a6005555f8268146a70e056467dafea60c
parent063c1723a6c2c0259fde18efa969cbbd62dcc73b (diff)
parent62a280b2c2489b2fa99a54e806d987bd0bf0039a (diff)
downloadfsck_msdos-482403793438098b8e613ebb24bb6ae1046aeef3.tar.gz
Sync with upstream 667eef4ac (svn revision 366064 + 366065).
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. Bug: 167345711 Change-Id: Ica05e89fdbf3c9078a0939be340a045e00460eb0
-rw-r--r--dir.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/dir.c b/dir.c
index 6bdc3b4..010bd65 100644
--- a/dir.c
+++ b/dir.c
@@ -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, struct dosDirEntry *dir)
} 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,10 +413,16 @@ checksize(struct fat_descriptor *fat, u_char *p, struct dosDirEntry *dir)
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",
+ pwarn("size of %s is %u, should at most be %" PRIu64 "\n",
fullpath(dir), dir->size, physicalSize);
if (ask(1, "Truncate")) {
dir->size = physicalSize;