Skip to content

Commit 476189c

Browse files
Tetsuhiro Kohadanamjaejeon
authored andcommitted
exfat: add boot region verification
Add Boot-Regions verification specified in exFAT specification. Note that the checksum type is strongly related to the raw structure, so the'u32 'type is used to clarify the number of bits. Signed-off-by: Tetsuhiro Kohada <[email protected]> Reviewed-by: Sungjong Seo <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent 33404a1 commit 476189c

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

fs/exfat/exfat_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
514514
u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
515515
unsigned short exfat_calc_chksum_2byte(void *data, int len,
516516
unsigned short chksum, int type);
517+
u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type);
517518
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync);
518519
void exfat_chain_set(struct exfat_chain *ec, unsigned int dir,
519520
unsigned int size, unsigned char flags);

fs/exfat/misc.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,20 @@ unsigned short exfat_calc_chksum_2byte(void *data, int len,
151151
return chksum;
152152
}
153153

154+
u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type)
155+
{
156+
int i;
157+
u8 *c = (u8 *)data;
158+
159+
for (i = 0; i < len; i++, c++) {
160+
if (unlikely(type == CS_BOOT_SECTOR &&
161+
(i == 106 || i == 107 || i == 112)))
162+
continue;
163+
chksum = ((chksum << 31) | (chksum >> 1)) + *c;
164+
}
165+
return chksum;
166+
}
167+
154168
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync)
155169
{
156170
set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(sb)->s_state);

fs/exfat/super.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,50 @@ static int exfat_read_boot_sector(struct super_block *sb)
491491
return 0;
492492
}
493493

494+
static int exfat_verify_boot_region(struct super_block *sb)
495+
{
496+
struct buffer_head *bh = NULL;
497+
u32 chksum = 0;
498+
__le32 *p_sig, *p_chksum;
499+
int sn, i;
500+
501+
/* read boot sector sub-regions */
502+
for (sn = 0; sn < 11; sn++) {
503+
bh = sb_bread(sb, sn);
504+
if (!bh)
505+
return -EIO;
506+
507+
if (sn != 0 && sn <= 8) {
508+
/* extended boot sector sub-regions */
509+
p_sig = (__le32 *)&bh->b_data[sb->s_blocksize - 4];
510+
if (le32_to_cpu(*p_sig) != EXBOOT_SIGNATURE)
511+
exfat_warn(sb, "Invalid exboot-signature(sector = %d): 0x%08x",
512+
sn, le32_to_cpu(*p_sig));
513+
}
514+
515+
chksum = exfat_calc_chksum32(bh->b_data, sb->s_blocksize,
516+
chksum, sn ? CS_DEFAULT : CS_BOOT_SECTOR);
517+
brelse(bh);
518+
}
519+
520+
/* boot checksum sub-regions */
521+
bh = sb_bread(sb, sn);
522+
if (!bh)
523+
return -EIO;
524+
525+
for (i = 0; i < sb->s_blocksize; i += sizeof(u32)) {
526+
p_chksum = (__le32 *)&bh->b_data[i];
527+
if (le32_to_cpu(*p_chksum) != chksum) {
528+
exfat_err(sb, "Invalid boot checksum (boot checksum : 0x%08x, checksum : 0x%08x)",
529+
le32_to_cpu(*p_chksum), chksum);
530+
brelse(bh);
531+
return -EINVAL;
532+
}
533+
}
534+
brelse(bh);
535+
return 0;
536+
}
537+
494538
/* mount the file system volume */
495539
static int __exfat_fill_super(struct super_block *sb)
496540
{
@@ -503,6 +547,12 @@ static int __exfat_fill_super(struct super_block *sb)
503547
goto free_bh;
504548
}
505549

550+
ret = exfat_verify_boot_region(sb);
551+
if (ret) {
552+
exfat_err(sb, "invalid boot region");
553+
goto free_bh;
554+
}
555+
506556
ret = exfat_create_upcase_table(sb);
507557
if (ret) {
508558
exfat_err(sb, "failed to load upcase table");

0 commit comments

Comments
 (0)