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 <kohada...@gmail.com>
---
 fs/exfat/exfat_fs.h |  1 +
 fs/exfat/misc.c     | 14 +++++++++++++
 fs/exfat/super.c    | 50 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)

diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index b0e5b9afc56c..15817281b3c8 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -517,6 +517,7 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct 
timespec64 *ts,
                u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
 unsigned short exfat_calc_chksum_2byte(void *data, int len,
                unsigned short chksum, int type);
+u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type);
 void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync);
 void exfat_chain_set(struct exfat_chain *ec, unsigned int dir,
                unsigned int size, unsigned char flags);
diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c
index ab7f88b1f6d3..b82d2dd5bd7c 100644
--- a/fs/exfat/misc.c
+++ b/fs/exfat/misc.c
@@ -151,6 +151,20 @@ unsigned short exfat_calc_chksum_2byte(void *data, int len,
        return chksum;
 }
 
+u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type)
+{
+       int i;
+       u8 *c = (u8 *)data;
+
+       for (i = 0; i < len; i++, c++) {
+               if (unlikely(type == CS_BOOT_SECTOR &&
+                            (i == 106 || i == 107 || i == 112)))
+                       continue;
+               chksum = ((chksum << 31) | (chksum >> 1)) + *c;
+       }
+       return chksum;
+}
+
 void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync)
 {
        set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(sb)->s_state);
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 95909b4d5e75..42b3bd3df020 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -486,6 +486,50 @@ static int exfat_read_boot_sector(struct super_block *sb)
        return 0;
 }
 
+static int exfat_verify_boot_region(struct super_block *sb)
+{
+       struct buffer_head *bh = NULL;
+       u32 chksum = 0, *p_sig, *p_chksum;
+       int sn, i;
+
+       /* read boot sector sub-regions */
+       for (sn = 0; sn < 11; sn++) {
+               bh = sb_bread(sb, sn);
+               if (!bh)
+                       return -EIO;
+
+               if (sn != 0 && sn <= 8) {
+                       /* extended boot sector sub-regions */
+                       p_sig = (u32 *)&bh->b_data[sb->s_blocksize - 4];
+                       if (le32_to_cpu(*p_sig) != EXBOOT_SIGNATURE) {
+                               exfat_err(sb, "no exboot-signature");
+                               brelse(bh);
+                               return -EINVAL;
+                       }
+               }
+
+               chksum = exfat_calc_chksum32(bh->b_data, sb->s_blocksize,
+                       chksum, sn ? CS_DEFAULT : CS_BOOT_SECTOR);
+               brelse(bh);
+       }
+
+       /* boot checksum sub-regions */
+       bh = sb_bread(sb, sn);
+       if (!bh)
+               return -EIO;
+
+       for (i = 0; i < sb->s_blocksize; i += sizeof(u32)) {
+               p_chksum = (u32 *)&bh->b_data[i];
+               if (le32_to_cpu(*p_chksum) != chksum) {
+                       exfat_err(sb, "mismatch checksum");
+                       brelse(bh);
+                       return -EINVAL;
+               }
+       }
+       brelse(bh);
+       return 0;
+}
+
 /* mount the file system volume */
 static int __exfat_fill_super(struct super_block *sb)
 {
@@ -498,6 +542,12 @@ static int __exfat_fill_super(struct super_block *sb)
                goto free_bh;
        }
 
+       ret = exfat_verify_boot_region(sb);
+       if (ret) {
+               exfat_err(sb, "invalid boot region");
+               goto free_bh;
+       }
+
        ret = exfat_create_upcase_table(sb);
        if (ret) {
                exfat_err(sb, "failed to load upcase table");
-- 
2.25.1

Reply via email to