Blame SOURCES/0032-exfat-add-boot-region-verification.patch

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