Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions fs/exfat/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,8 @@ static int exfat_calibrate_blocksize(struct super_block *sb, int logical_sect)
}

if (logical_sect > sb->s_blocksize) {
const unsigned long saved_bs = sb->s_blocksize;

brelse(sbi->boot_bh);
sbi->boot_bh = NULL;

Expand All @@ -423,6 +425,10 @@ static int exfat_calibrate_blocksize(struct super_block *sb, int logical_sect)
sb->s_blocksize);
return -EIO;
}

exfat_warn(sb, "blocksize calibrated from device logical block size(%lu) to volume sector size(%d)!\n"
"Other implementations may not be able to handle this volume.",
saved_bs, logical_sect);
}
return 0;
}
Expand All @@ -431,6 +437,7 @@ static int exfat_read_boot_sector(struct super_block *sb)
{
struct boot_sector *p_boot;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned int nb_clusters;

/* set block size to read super block */
if (!sb_min_blocksize(sb, 512)) {
Expand Down Expand Up @@ -501,8 +508,17 @@ static int exfat_read_boot_sector(struct super_block *sb)
sbi->data_start_sector = le32_to_cpu(p_boot->clu_offset);
sbi->num_sectors = le64_to_cpu(p_boot->vol_length);
/* because the cluster index starts with 2 */
sbi->num_clusters = le32_to_cpu(p_boot->clu_count) +
EXFAT_RESERVED_CLUSTERS;
nb_clusters = le32_to_cpu(p_boot->clu_count);
/*
* The inclusive comparison in the following check seems a bit off(quite
* literally), but the exFAT format section 3.1.9 says
* "lesser of the following". Aye, aye, captain.
*/
if (nb_clusters >= EXFAT_MAX_NUM_CLUSTER) {
exfat_err(sb, "bogus number of clusters : %u", nb_clusters);
return -EINVAL;
}
sbi->num_clusters = nb_clusters + EXFAT_RESERVED_CLUSTERS;

sbi->root_dir = le32_to_cpu(p_boot->root_cluster);
sbi->dentries_per_clu = 1 <<
Expand Down Expand Up @@ -586,6 +602,34 @@ static int exfat_verify_boot_region(struct super_block *sb)
return 0;
}

static inline int exfat_check_volume_sizes(struct super_block *sb)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
/* last sector of exFAT volume == end of last cluster */
const sector_t lc_end = exfat_cluster_to_sector(sbi, sbi->num_clusters);
/*
* Do the calculations in bytes because the blocksize may have been
* calibrated in exfat_calibrate_blocksize(), and bdev_nr_sectors()
* always reports in 512-byte units.
*/
const unsigned long long vol_size = EXFAT_BLK_TO_B(sbi->num_sectors, sb);
const unsigned long long bdev_size = (unsigned long long)bdev_nr_bytes(sb->s_bdev);

if (sbi->num_sectors < (unsigned long long)lc_end) {
exfat_err(sb, "number of clusters out of volume length bounds : num_sectors=%llu, last_cluster_sector=%lld",
sbi->num_sectors, lc_end);
return -EINVAL;
}

if (bdev_size < vol_size) {
exfat_err(sb, "volume length out of bounds : dev=%llu, vol=%lld",
bdev_size, vol_size);
return -EINVAL;
}

return 0;
}

/* mount the file system volume */
static int __exfat_fill_super(struct super_block *sb,
struct exfat_chain *root_clu)
Expand All @@ -605,6 +649,12 @@ static int __exfat_fill_super(struct super_block *sb,
goto free_bh;
}

ret = exfat_check_volume_sizes(sb);
if (ret) {
exfat_warn(sb, "volume bounds check failed. Please run fsck");
goto free_bh;
}

/*
* Call exfat_count_num_cluster() before searching for up-case and
* bitmap directory entries to avoid infinite loop if they are missing
Expand Down Expand Up @@ -652,6 +702,7 @@ static int __exfat_fill_super(struct super_block *sb,
exfat_free_bitmap(sbi);
free_bh:
brelse(sbi->boot_bh);
exfat_free_upcase_table(sbi);
return ret;
}

Expand Down Expand Up @@ -747,6 +798,7 @@ static int exfat_get_tree(struct fs_context *fc)

static void exfat_free_sbi(struct exfat_sb_info *sbi)
{
exfat_free_upcase_table(sbi);
exfat_free_iocharset(sbi);
kfree(sbi);
}
Expand Down
Loading