Permalink
Browse files

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>
  • Loading branch information...
andreasbombe committed Apr 27, 2016
1 parent 016800e commit e8eff147e9da1185f9afd5b25948153a3b97cf52
Showing with 12 additions and 4 deletions.
  1. +11 −3 src/boot.c
  2. +1 −1 src/fsck.fat.h
View
@@ -103,8 +103,8 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss)
(unsigned long long)fs->fat_start,
(unsigned long long)fs->fat_start / lss);
printf("%10d FATs, %d bit entries\n", b->fats, fs->fat_bits);
- printf("%10d bytes per FAT (= %u sectors)\n", fs->fat_size,
- fs->fat_size / lss);
+ printf("%10lld bytes per FAT (= %llu sectors)\n", (long long)fs->fat_size,
+ (long long)fs->fat_size / lss);
if (!fs->root_cluster) {
printf("Root directory starts at byte %llu (sector %llu)\n",
(unsigned long long)fs->root_start,
@@ -329,7 +329,7 @@ void read_boot(DOS_FS * fs)
struct boot_sector b;
unsigned total_sectors;
unsigned short logical_sector_size, sectors;
- unsigned fat_length;
+ off_t fat_length;
unsigned total_fat_entries;
off_t data_size;
@@ -358,16 +358,24 @@ void read_boot(DOS_FS * fs)
/* Can't access last odd sector anyway, so round down */
fs_test((off_t)((total_sectors & ~1) - 1) * logical_sector_size,
logical_sector_size);
+
fat_length = le16toh(b.fat_length) ?
le16toh(b.fat_length) : le32toh(b.fat32_length);
+ if (!fat_length)
+ die("FAT size is zero.");
+
fs->fat_start = (off_t)le16toh(b.reserved) * logical_sector_size;
fs->root_start = ((off_t)le16toh(b.reserved) + b.fats * fat_length) *
logical_sector_size;
fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
fs->data_start = fs->root_start + ROUND_TO_MULTIPLE(fs->root_entries <<
MSDOS_DIR_BITS,
logical_sector_size);
+
data_size = (off_t)total_sectors * logical_sector_size - fs->data_start;
+ if (data_size < fs->cluster_size)
+ die("Filesystem has no space for any data clusters");
+
fs->data_clusters = data_size / fs->cluster_size;
fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
fs->fsinfo_start = 0; /* no FSINFO structure */
View
@@ -152,7 +152,7 @@ typedef struct {
typedef struct {
int nfats;
off_t fat_start;
- unsigned int fat_size; /* unit is bytes */
+ off_t fat_size; /* unit is bytes */
unsigned int fat_bits; /* size of a FAT entry */
unsigned int eff_fat_bits; /* # of used bits in a FAT entry */
uint32_t root_cluster; /* 0 for old-style root dir */

0 comments on commit e8eff14

Please sign in to comment.