Skip to content

Commit 33404a1

Browse files
Tetsuhiro Kohadanamjaejeon
authored andcommitted
exfat: separate the boot sector analysis
Separate the boot sector analysis to read_boot_sector(). And add a check for the fs_name field. Furthermore, add a strict consistency check, because overlapping areas can cause serious corruption. Signed-off-by: Tetsuhiro Kohada <[email protected]> Reviewed-by: Sungjong Seo <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent 181a9e8 commit 33404a1

File tree

2 files changed

+56
-43
lines changed

2 files changed

+56
-43
lines changed

fs/exfat/exfat_raw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010

1111
#define BOOT_SIGNATURE 0xAA55
1212
#define EXBOOT_SIGNATURE 0xAA550000
13+
#define STR_EXFAT "EXFAT " /* size should be 8 */
1314

1415
#define EXFAT_MAX_FILE_LEN 255
1516

1617
#define VOL_CLEAN 0x0000
1718
#define VOL_DIRTY 0x0002
19+
#define ERR_MEDIUM 0x0004
1820

1921
#define EXFAT_EOF_CLUSTER 0xFFFFFFFFu
2022
#define EXFAT_BAD_CLUSTER 0xFFFFFFF7u

fs/exfat/super.c

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -366,25 +366,20 @@ static int exfat_read_root(struct inode *inode)
366366
return 0;
367367
}
368368

369-
static struct boot_sector *exfat_read_boot_with_logical_sector(
370-
struct super_block *sb)
369+
static int exfat_calibrate_blocksize(struct super_block *sb, int logical_sect)
371370
{
372371
struct exfat_sb_info *sbi = EXFAT_SB(sb);
373-
struct boot_sector *p_boot = (struct boot_sector *)sbi->boot_bh->b_data;
374-
unsigned short logical_sect = 0;
375-
376-
logical_sect = 1 << p_boot->sect_size_bits;
377372

378373
if (!is_power_of_2(logical_sect) ||
379374
logical_sect < 512 || logical_sect > 4096) {
380375
exfat_err(sb, "bogus logical sector size %u", logical_sect);
381-
return NULL;
376+
return -EIO;
382377
}
383378

384379
if (logical_sect < sb->s_blocksize) {
385380
exfat_err(sb, "logical sector size too small for device (logical sector size = %u)",
386381
logical_sect);
387-
return NULL;
382+
return -EIO;
388383
}
389384

390385
if (logical_sect > sb->s_blocksize) {
@@ -394,24 +389,20 @@ static struct boot_sector *exfat_read_boot_with_logical_sector(
394389
if (!sb_set_blocksize(sb, logical_sect)) {
395390
exfat_err(sb, "unable to set blocksize %u",
396391
logical_sect);
397-
return NULL;
392+
return -EIO;
398393
}
399394
sbi->boot_bh = sb_bread(sb, 0);
400395
if (!sbi->boot_bh) {
401396
exfat_err(sb, "unable to read boot sector (logical sector size = %lu)",
402397
sb->s_blocksize);
403-
return NULL;
398+
return -EIO;
404399
}
405-
406-
p_boot = (struct boot_sector *)sbi->boot_bh->b_data;
407400
}
408-
return p_boot;
401+
return 0;
409402
}
410403

411-
/* mount the file system volume */
412-
static int __exfat_fill_super(struct super_block *sb)
404+
static int exfat_read_boot_sector(struct super_block *sb)
413405
{
414-
int ret;
415406
struct boot_sector *p_boot;
416407
struct exfat_sb_info *sbi = EXFAT_SB(sb);
417408

@@ -424,51 +415,41 @@ static int __exfat_fill_super(struct super_block *sb)
424415
exfat_err(sb, "unable to read boot sector");
425416
return -EIO;
426417
}
427-
428-
/* PRB is read */
429418
p_boot = (struct boot_sector *)sbi->boot_bh->b_data;
430419

431420
/* check the validity of BOOT */
432421
if (le16_to_cpu((p_boot->signature)) != BOOT_SIGNATURE) {
433422
exfat_err(sb, "invalid boot record signature");
434-
ret = -EINVAL;
435-
goto free_bh;
423+
return -EINVAL;
436424
}
437425

438-
439-
/* check logical sector size */
440-
p_boot = exfat_read_boot_with_logical_sector(sb);
441-
if (!p_boot) {
442-
ret = -EIO;
443-
goto free_bh;
426+
if (memcmp(p_boot->fs_name, STR_EXFAT, BOOTSEC_FS_NAME_LEN)) {
427+
exfat_err(sb, "invalid fs_name"); /* fs_name may unprintable */
428+
return -EINVAL;
444429
}
445430

446431
/*
447-
* res_zero field must be filled with zero to prevent mounting
432+
* must_be_zero field must be filled with zero to prevent mounting
448433
* from FAT volume.
449434
*/
450-
if (memchr_inv(p_boot->must_be_zero, 0,
451-
sizeof(p_boot->must_be_zero))) {
452-
ret = -EINVAL;
453-
goto free_bh;
454-
}
435+
if (memchr_inv(p_boot->must_be_zero, 0, sizeof(p_boot->must_be_zero)))
436+
return -EINVAL;
455437

456-
p_boot = (struct boot_sector *)p_boot;
457-
if (!p_boot->num_fats) {
438+
if (p_boot->num_fats != 1 && p_boot->num_fats != 2) {
458439
exfat_err(sb, "bogus number of FAT structure");
459-
ret = -EINVAL;
460-
goto free_bh;
440+
return -EINVAL;
461441
}
462442

463443
sbi->sect_per_clus = 1 << p_boot->sect_per_clus_bits;
464444
sbi->sect_per_clus_bits = p_boot->sect_per_clus_bits;
465-
sbi->cluster_size_bits = sbi->sect_per_clus_bits + sb->s_blocksize_bits;
445+
sbi->cluster_size_bits = p_boot->sect_per_clus_bits +
446+
p_boot->sect_size_bits;
466447
sbi->cluster_size = 1 << sbi->cluster_size_bits;
467448
sbi->num_FAT_sectors = le32_to_cpu(p_boot->fat_length);
468449
sbi->FAT1_start_sector = le32_to_cpu(p_boot->fat_offset);
469-
sbi->FAT2_start_sector = p_boot->num_fats == 1 ?
470-
sbi->FAT1_start_sector :
471-
sbi->FAT1_start_sector + sbi->num_FAT_sectors;
450+
sbi->FAT2_start_sector = le32_to_cpu(p_boot->fat_offset);
451+
if (p_boot->num_fats == 2)
452+
sbi->FAT2_start_sector += sbi->num_FAT_sectors;
472453
sbi->data_start_sector = le32_to_cpu(p_boot->clu_offset);
473454
sbi->num_sectors = le64_to_cpu(p_boot->vol_length);
474455
/* because the cluster index starts with 2 */
@@ -483,15 +464,45 @@ static int __exfat_fill_super(struct super_block *sb)
483464
sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER;
484465
sbi->used_clusters = EXFAT_CLUSTERS_UNTRACKED;
485466

486-
if (le16_to_cpu(p_boot->vol_flags) & VOL_DIRTY) {
487-
sbi->vol_flag |= VOL_DIRTY;
488-
exfat_warn(sb, "Volume was not properly unmounted. Some data may be corrupt. Please run fsck.");
467+
/* check consistencies */
468+
if (sbi->num_FAT_sectors << p_boot->sect_size_bits <
469+
sbi->num_clusters * 4) {
470+
exfat_err(sb, "bogus fat length");
471+
return -EINVAL;
472+
}
473+
if (sbi->data_start_sector <
474+
sbi->FAT1_start_sector + sbi->num_FAT_sectors * p_boot->num_fats) {
475+
exfat_err(sb, "bogus data start sector");
476+
return -EINVAL;
489477
}
478+
if (sbi->vol_flag & VOL_DIRTY)
479+
exfat_warn(sb, "Volume was not properly unmounted. Some data may be corrupt. Please run fsck.");
480+
if (sbi->vol_flag & ERR_MEDIUM)
481+
exfat_warn(sb, "Medium has reported failures. Some data may be lost.");
490482

491483
/* exFAT file size is limited by a disk volume size */
492484
sb->s_maxbytes = (u64)(sbi->num_clusters - EXFAT_RESERVED_CLUSTERS) <<
493485
sbi->cluster_size_bits;
494486

487+
/* check logical sector size */
488+
if (exfat_calibrate_blocksize(sb, 1 << p_boot->sect_size_bits))
489+
return -EIO;
490+
491+
return 0;
492+
}
493+
494+
/* mount the file system volume */
495+
static int __exfat_fill_super(struct super_block *sb)
496+
{
497+
int ret;
498+
struct exfat_sb_info *sbi = EXFAT_SB(sb);
499+
500+
ret = exfat_read_boot_sector(sb);
501+
if (ret) {
502+
exfat_err(sb, "failed to read boot sector");
503+
goto free_bh;
504+
}
505+
495506
ret = exfat_create_upcase_table(sb);
496507
if (ret) {
497508
exfat_err(sb, "failed to load upcase table");

0 commit comments

Comments
 (0)