|
Kmods SIG |
9e3ffb |
From 476189c0ef3b658de3f6b89fd0fdeb6dc451b564 Mon Sep 17 00:00:00 2001
|
|
Kmods SIG |
9e3ffb |
From: Tetsuhiro Kohada <kohada.t2@gmail.com>
|
|
Kmods SIG |
9e3ffb |
Date: Sun, 31 May 2020 18:30:17 +0900
|
|
Kmods SIG |
9e3ffb |
Subject: [Backport 476189c0ef3b] exfat: add boot region verification
|
|
Kmods SIG |
9e3ffb |
|
|
Kmods SIG |
9e3ffb |
Add Boot-Regions verification specified in exFAT specification.
|
|
Kmods SIG |
9e3ffb |
Note that the checksum type is strongly related to the raw structure,
|
|
Kmods SIG |
9e3ffb |
so the'u32 'type is used to clarify the number of bits.
|
|
Kmods SIG |
9e3ffb |
|
|
Kmods SIG |
9e3ffb |
Signed-off-by: Tetsuhiro Kohada <kohada.t2@gmail.com>
|
|
Kmods SIG |
9e3ffb |
Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
|
|
Kmods SIG |
9e3ffb |
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
|
|
Kmods SIG |
9e3ffb |
---
|
|
Kmods SIG |
9e3ffb |
src/exfat_fs.h | 1 +
|
|
Kmods SIG |
9e3ffb |
src/misc.c | 14 +++++++++++++
|
|
Kmods SIG |
9e3ffb |
src/super.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
|
|
Kmods SIG |
9e3ffb |
3 files changed, 65 insertions(+)
|
|
Kmods SIG |
9e3ffb |
|
|
Kmods SIG |
9e3ffb |
diff --git a/src/exfat_fs.h b/src/exfat_fs.h
|
|
Kmods SIG |
9e3ffb |
index 911f58b93f3d257bce04b645a2ada62d0f51a3c0..8c2a70bfaa10d4743c46aad74254e363d4079c74 100644
|
|
Kmods SIG |
9e3ffb |
--- a/src/exfat_fs.h
|
|
Kmods SIG |
9e3ffb |
+++ b/src/exfat_fs.h
|
|
Kmods SIG |
9e3ffb |
@@ -514,6 +514,7 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
|
|
Kmods SIG |
9e3ffb |
u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
|
|
Kmods SIG |
9e3ffb |
unsigned short exfat_calc_chksum_2byte(void *data, int len,
|
|
Kmods SIG |
9e3ffb |
unsigned short chksum, int type);
|
|
Kmods SIG |
9e3ffb |
+u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type);
|
|
Kmods SIG |
9e3ffb |
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync);
|
|
Kmods SIG |
9e3ffb |
void exfat_chain_set(struct exfat_chain *ec, unsigned int dir,
|
|
Kmods SIG |
9e3ffb |
unsigned int size, unsigned char flags);
|
|
Kmods SIG |
9e3ffb |
diff --git a/src/misc.c b/src/misc.c
|
|
Kmods SIG |
9e3ffb |
index ab7f88b1f6d3065cd3fca409526d50e833bbbfb0..b82d2dd5bd7cb291ffe5ed5091c9214593c32a69 100644
|
|
Kmods SIG |
9e3ffb |
--- a/src/misc.c
|
|
Kmods SIG |
9e3ffb |
+++ b/src/misc.c
|
|
Kmods SIG |
9e3ffb |
@@ -151,6 +151,20 @@ unsigned short exfat_calc_chksum_2byte(void *data, int len,
|
|
Kmods SIG |
9e3ffb |
return chksum;
|
|
Kmods SIG |
9e3ffb |
}
|
|
Kmods SIG |
9e3ffb |
|
|
Kmods SIG |
9e3ffb |
+u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type)
|
|
Kmods SIG |
9e3ffb |
+{
|
|
Kmods SIG |
9e3ffb |
+ int i;
|
|
Kmods SIG |
9e3ffb |
+ u8 *c = (u8 *)data;
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
+ for (i = 0; i < len; i++, c++) {
|
|
Kmods SIG |
9e3ffb |
+ if (unlikely(type == CS_BOOT_SECTOR &&
|
|
Kmods SIG |
9e3ffb |
+ (i == 106 || i == 107 || i == 112)))
|
|
Kmods SIG |
9e3ffb |
+ continue;
|
|
Kmods SIG |
9e3ffb |
+ chksum = ((chksum << 31) | (chksum >> 1)) + *c;
|
|
Kmods SIG |
9e3ffb |
+ }
|
|
Kmods SIG |
9e3ffb |
+ return chksum;
|
|
Kmods SIG |
9e3ffb |
+}
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync)
|
|
Kmods SIG |
9e3ffb |
{
|
|
Kmods SIG |
9e3ffb |
set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(sb)->s_state);
|
|
Kmods SIG |
9e3ffb |
diff --git a/src/super.c b/src/super.c
|
|
Kmods SIG |
9e3ffb |
index 6a1330be5a9a4b58e2a39b197788f139bfbaba4f..405717e4e3eac6b3233e1e57b0bcc70f56f1c42f 100644
|
|
Kmods SIG |
9e3ffb |
--- a/src/super.c
|
|
Kmods SIG |
9e3ffb |
+++ b/src/super.c
|
|
Kmods SIG |
9e3ffb |
@@ -491,6 +491,50 @@ static int exfat_read_boot_sector(struct super_block *sb)
|
|
Kmods SIG |
9e3ffb |
return 0;
|
|
Kmods SIG |
9e3ffb |
}
|
|
Kmods SIG |
9e3ffb |
|
|
Kmods SIG |
9e3ffb |
+static int exfat_verify_boot_region(struct super_block *sb)
|
|
Kmods SIG |
9e3ffb |
+{
|
|
Kmods SIG |
9e3ffb |
+ struct buffer_head *bh = NULL;
|
|
Kmods SIG |
9e3ffb |
+ u32 chksum = 0;
|
|
Kmods SIG |
9e3ffb |
+ __le32 *p_sig, *p_chksum;
|
|
Kmods SIG |
9e3ffb |
+ int sn, i;
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
+ /* read boot sector sub-regions */
|
|
Kmods SIG |
9e3ffb |
+ for (sn = 0; sn < 11; sn++) {
|
|
Kmods SIG |
9e3ffb |
+ bh = sb_bread(sb, sn);
|
|
Kmods SIG |
9e3ffb |
+ if (!bh)
|
|
Kmods SIG |
9e3ffb |
+ return -EIO;
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
+ if (sn != 0 && sn <= 8) {
|
|
Kmods SIG |
9e3ffb |
+ /* extended boot sector sub-regions */
|
|
Kmods SIG |
9e3ffb |
+ p_sig = (__le32 *)&bh->b_data[sb->s_blocksize - 4];
|
|
Kmods SIG |
9e3ffb |
+ if (le32_to_cpu(*p_sig) != EXBOOT_SIGNATURE)
|
|
Kmods SIG |
9e3ffb |
+ exfat_warn(sb, "Invalid exboot-signature(sector = %d): 0x%08x",
|
|
Kmods SIG |
9e3ffb |
+ sn, le32_to_cpu(*p_sig));
|
|
Kmods SIG |
9e3ffb |
+ }
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
+ chksum = exfat_calc_chksum32(bh->b_data, sb->s_blocksize,
|
|
Kmods SIG |
9e3ffb |
+ chksum, sn ? CS_DEFAULT : CS_BOOT_SECTOR);
|
|
Kmods SIG |
9e3ffb |
+ brelse(bh);
|
|
Kmods SIG |
9e3ffb |
+ }
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
+ /* boot checksum sub-regions */
|
|
Kmods SIG |
9e3ffb |
+ bh = sb_bread(sb, sn);
|
|
Kmods SIG |
9e3ffb |
+ if (!bh)
|
|
Kmods SIG |
9e3ffb |
+ return -EIO;
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
+ for (i = 0; i < sb->s_blocksize; i += sizeof(u32)) {
|
|
Kmods SIG |
9e3ffb |
+ p_chksum = (__le32 *)&bh->b_data[i];
|
|
Kmods SIG |
9e3ffb |
+ if (le32_to_cpu(*p_chksum) != chksum) {
|
|
Kmods SIG |
9e3ffb |
+ exfat_err(sb, "Invalid boot checksum (boot checksum : 0x%08x, checksum : 0x%08x)",
|
|
Kmods SIG |
9e3ffb |
+ le32_to_cpu(*p_chksum), chksum);
|
|
Kmods SIG |
9e3ffb |
+ brelse(bh);
|
|
Kmods SIG |
9e3ffb |
+ return -EINVAL;
|
|
Kmods SIG |
9e3ffb |
+ }
|
|
Kmods SIG |
9e3ffb |
+ }
|
|
Kmods SIG |
9e3ffb |
+ brelse(bh);
|
|
Kmods SIG |
9e3ffb |
+ return 0;
|
|
Kmods SIG |
9e3ffb |
+}
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
/* mount the file system volume */
|
|
Kmods SIG |
9e3ffb |
static int __exfat_fill_super(struct super_block *sb)
|
|
Kmods SIG |
9e3ffb |
{
|
|
Kmods SIG |
9e3ffb |
@@ -503,6 +547,12 @@ static int __exfat_fill_super(struct super_block *sb)
|
|
Kmods SIG |
9e3ffb |
goto free_bh;
|
|
Kmods SIG |
9e3ffb |
}
|
|
Kmods SIG |
9e3ffb |
|
|
Kmods SIG |
9e3ffb |
+ ret = exfat_verify_boot_region(sb);
|
|
Kmods SIG |
9e3ffb |
+ if (ret) {
|
|
Kmods SIG |
9e3ffb |
+ exfat_err(sb, "invalid boot region");
|
|
Kmods SIG |
9e3ffb |
+ goto free_bh;
|
|
Kmods SIG |
9e3ffb |
+ }
|
|
Kmods SIG |
9e3ffb |
+
|
|
Kmods SIG |
9e3ffb |
ret = exfat_create_upcase_table(sb);
|
|
Kmods SIG |
9e3ffb |
if (ret) {
|
|
Kmods SIG |
9e3ffb |
exfat_err(sb, "failed to load upcase table");
|
|
Kmods SIG |
9e3ffb |
--
|
|
Kmods SIG |
9e3ffb |
2.31.1
|
|
Kmods SIG |
9e3ffb |
|