diff mbox series

[4/5] staging: exfat: add boot region verification

Message ID 20200311105245.125564-4-Kohada.Tetsuhiro@dc.MitsubishiElectric.co.jp (mailing list archive)
State New, archived
Headers show
Series [1/5] staging: exfat: conform 'pbr_sector_t' definition to exFAT specification | expand

Commit Message

Kohada.Tetsuhiro@dc.MitsubishiElectric.co.jp March 11, 2020, 10:52 a.m. UTC
Add Boot-Regions verification specified in exFAT specification.

Reviewed-by: Takahiro Mori <Mori.Takahiro@ab.MitsubishiElectric.co.jp>
Signed-off-by: Tetsuhiro Kohada <Kohada.Tetsuhiro@dc.MitsubishiElectric.co.jp>
---
 drivers/staging/exfat/exfat_core.c | 69 ++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
diff mbox series

Patch

diff --git a/drivers/staging/exfat/exfat_core.c b/drivers/staging/exfat/exfat_core.c
index 3faa7f35c77c..07c876bb1759 100644
--- a/drivers/staging/exfat/exfat_core.c
+++ b/drivers/staging/exfat/exfat_core.c
@@ -2017,7 +2017,20 @@  u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type)
 			chksum = (((chksum & 1) << 15) |
 				  ((chksum & 0xFFFE) >> 1)) + (u16)*c;
 	}
+	return chksum;
+}
 
+u32 calc_checksum32(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 & 1) << 31 | chksum >> 1) + (u32)*c;
+	}
 	return chksum;
 }
 
@@ -2053,6 +2066,58 @@  s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir,
 	return 0;
 }
 
+static int verify_boot_region(struct super_block *sb)
+{
+	struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+	struct buffer_head *tmp_bh = NULL;
+	u32 chksum = 0, *p_signatue, *p_chksum;
+	int sn = 0, i, ret;
+
+	/* read boot sector sub-regions */
+	ret = sector_read(sb, sn++, &tmp_bh, 1);
+	if (ret)
+		goto out;
+
+	chksum = calc_checksum32(tmp_bh->b_data, p_bd->sector_size,
+				 chksum, CS_BOOT_SECTOR);
+
+	while (sn < 11) {
+		ret = sector_read(sb, sn++, &tmp_bh, 1);
+		if (ret)
+			goto out;
+
+		chksum = calc_checksum32(tmp_bh->b_data, p_bd->sector_size,
+					 chksum, CS_DEFAULT);
+
+		/* skip OEM Parameters & Reserved sub-regions */
+		if (sn >= 9)
+			continue;
+
+		/* extended boot sector sub-regions */
+		p_signatue = (u32 *)(tmp_bh->b_data + p_bd->sector_size - 4);
+		if (le32_to_cpu(*p_signatue) != EXBOOT_SIGNATURE) {
+			ret = -EFSCORRUPTED;
+			goto out;
+		}
+	}
+
+	/* boot checksum sub-regions */
+	ret = sector_read(sb, sn++, &tmp_bh, 1);
+	if (ret)
+		goto out;
+
+	p_chksum = (u32 *)tmp_bh->b_data;
+	for (i = 0; i < p_bd->sector_size / 4; i++) {
+		if (le32_to_cpu(*p_chksum) != chksum) {
+			ret = -EFSCORRUPTED;
+			goto out;
+		}
+	}
+out:
+	brelse(tmp_bh);
+	return ret;
+}
+
 static int read_boot_sector(struct super_block *sb)
 {
 	struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
@@ -2129,6 +2194,10 @@  s32 exfat_mount(struct super_block *sb)
 	if (ret)
 		goto err_out;
 
+	ret = verify_boot_region(sb);
+	if (ret)
+		goto err_out;
+
 	ret = load_alloc_bitmap(sb);
 	if (ret)
 		goto err_out;