Skip to content

Commit e8eff14

Browse files
committed
read_boot(): Handle excessive FAT size specifications
The variable used for storing the FAT size (in bytes) was an unsigned int. Since the size in sectors read from the BPB was not sufficiently checked, this could end up being zero after multiplying it with the sector size while some offsets still stayed excessive. Ultimately it would cause segfaults when accessing FAT entries for which no memory was allocated. Make it more robust by changing the types used to store FAT size to off_t and abort if there is no room for data clusters. Additionally check that FAT size is not specified as zero. Fixes #25 and fixes #26. Reported-by: Hanno Böck Signed-off-by: Andreas Bombe <aeb@debian.org>
1 parent 016800e commit e8eff14

File tree

2 files changed

+12
-4
lines changed

2 files changed

+12
-4
lines changed

Diff for: src/boot.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss)
103103
(unsigned long long)fs->fat_start,
104104
(unsigned long long)fs->fat_start / lss);
105105
printf("%10d FATs, %d bit entries\n", b->fats, fs->fat_bits);
106-
printf("%10d bytes per FAT (= %u sectors)\n", fs->fat_size,
107-
fs->fat_size / lss);
106+
printf("%10lld bytes per FAT (= %llu sectors)\n", (long long)fs->fat_size,
107+
(long long)fs->fat_size / lss);
108108
if (!fs->root_cluster) {
109109
printf("Root directory starts at byte %llu (sector %llu)\n",
110110
(unsigned long long)fs->root_start,
@@ -329,7 +329,7 @@ void read_boot(DOS_FS * fs)
329329
struct boot_sector b;
330330
unsigned total_sectors;
331331
unsigned short logical_sector_size, sectors;
332-
unsigned fat_length;
332+
off_t fat_length;
333333
unsigned total_fat_entries;
334334
off_t data_size;
335335

@@ -358,16 +358,24 @@ void read_boot(DOS_FS * fs)
358358
/* Can't access last odd sector anyway, so round down */
359359
fs_test((off_t)((total_sectors & ~1) - 1) * logical_sector_size,
360360
logical_sector_size);
361+
361362
fat_length = le16toh(b.fat_length) ?
362363
le16toh(b.fat_length) : le32toh(b.fat32_length);
364+
if (!fat_length)
365+
die("FAT size is zero.");
366+
363367
fs->fat_start = (off_t)le16toh(b.reserved) * logical_sector_size;
364368
fs->root_start = ((off_t)le16toh(b.reserved) + b.fats * fat_length) *
365369
logical_sector_size;
366370
fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
367371
fs->data_start = fs->root_start + ROUND_TO_MULTIPLE(fs->root_entries <<
368372
MSDOS_DIR_BITS,
369373
logical_sector_size);
374+
370375
data_size = (off_t)total_sectors * logical_sector_size - fs->data_start;
376+
if (data_size < fs->cluster_size)
377+
die("Filesystem has no space for any data clusters");
378+
371379
fs->data_clusters = data_size / fs->cluster_size;
372380
fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
373381
fs->fsinfo_start = 0; /* no FSINFO structure */

Diff for: src/fsck.fat.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ typedef struct {
152152
typedef struct {
153153
int nfats;
154154
off_t fat_start;
155-
unsigned int fat_size; /* unit is bytes */
155+
off_t fat_size; /* unit is bytes */
156156
unsigned int fat_bits; /* size of a FAT entry */
157157
unsigned int eff_fat_bits; /* # of used bits in a FAT entry */
158158
uint32_t root_cluster; /* 0 for old-style root dir */

0 commit comments

Comments
 (0)