linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/4 v4] exfat: add boot region verification
@ 2020-05-31  9:30 ` Tetsuhiro Kohada
  2020-06-01 12:21   ` Sungjong Seo
  0 siblings, 1 reply; 2+ messages in thread
From: Tetsuhiro Kohada @ 2020-05-31  9:30 UTC (permalink / raw)
  To: kohada.t2
  Cc: kohada.tetsuhiro, mori.takahiro, motai.hirotaka, Namjae Jeon,
	Sungjong Seo, linux-fsdevel, linux-kernel

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.t2@gmail.com>
---
Changes in v2:
 - rebase with patch 'optimize dir-cache' applied
 - just print a warning when invalid exboot-signature detected
 - print additional information when invalid boot-checksum detected
Changes in v3:
 - based on '[PATCH 2/4 v3] exfat: separate the boot sector analysis'
Changes in v4:
 - fix type of p_sig/p_chksum to __le32

 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 9673e2d31045..eebbe5a84b2b 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -514,6 +514,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 6a1330be5a9a..405717e4e3ea 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -491,6 +491,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;
+	__le32 *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 = (__le32 *)&bh->b_data[sb->s_blocksize - 4];
+			if (le32_to_cpu(*p_sig) != EXBOOT_SIGNATURE)
+				exfat_warn(sb, "Invalid exboot-signature(sector = %d): 0x%08x",
+					   sn, le32_to_cpu(*p_sig));
+		}
+
+		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 = (__le32 *)&bh->b_data[i];
+		if (le32_to_cpu(*p_chksum) != chksum) {
+			exfat_err(sb, "Invalid boot checksum (boot checksum : 0x%08x, checksum : 0x%08x)",
+				  le32_to_cpu(*p_chksum), chksum);
+			brelse(bh);
+			return -EINVAL;
+		}
+	}
+	brelse(bh);
+	return 0;
+}
+
 /* mount the file system volume */
 static int __exfat_fill_super(struct super_block *sb)
 {
@@ -503,6 +547,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


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* RE: [PATCH 3/4 v4] exfat: add boot region verification
  2020-05-31  9:30 ` [PATCH 3/4 v4] exfat: add boot region verification Tetsuhiro Kohada
@ 2020-06-01 12:21   ` Sungjong Seo
  0 siblings, 0 replies; 2+ messages in thread
From: Sungjong Seo @ 2020-06-01 12:21 UTC (permalink / raw)
  To: 'Tetsuhiro Kohada'
  Cc: kohada.tetsuhiro, mori.takahiro, motai.hirotaka,
	'Namjae Jeon',
	linux-fsdevel, linux-kernel

> 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.t2@gmail.com>

Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>

> ---
> Changes in v2:
>  - rebase with patch 'optimize dir-cache' applied
>  - just print a warning when invalid exboot-signature detected
>  - print additional information when invalid boot-checksum detected
> Changes in v3:
>  - based on '[PATCH 2/4 v3] exfat: separate the boot sector analysis'
> Changes in v4:
>  - fix type of p_sig/p_chksum to __le32
> 
>  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
> 9673e2d31045..eebbe5a84b2b 100644
> --- a/fs/exfat/exfat_fs.h
> +++ b/fs/exfat/exfat_fs.h
> @@ -514,6 +514,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 6a1330be5a9a..405717e4e3ea
> 100644
> --- a/fs/exfat/super.c
> +++ b/fs/exfat/super.c
> @@ -491,6 +491,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;
> +	__le32 *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 = (__le32 *)&bh->b_data[sb->s_blocksize - 4];
> +			if (le32_to_cpu(*p_sig) != EXBOOT_SIGNATURE)
> +				exfat_warn(sb, "Invalid
exboot-signature(sector
> = %d): 0x%08x",
> +					   sn, le32_to_cpu(*p_sig));
> +		}
> +
> +		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 = (__le32 *)&bh->b_data[i];
> +		if (le32_to_cpu(*p_chksum) != chksum) {
> +			exfat_err(sb, "Invalid boot checksum (boot checksum
:
> 0x%08x, checksum : 0x%08x)",
> +				  le32_to_cpu(*p_chksum), chksum);
> +			brelse(bh);
> +			return -EINVAL;
> +		}
> +	}
> +	brelse(bh);
> +	return 0;
> +}
> +
>  /* mount the file system volume */
>  static int __exfat_fill_super(struct super_block *sb)  { @@ -503,6
> +547,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



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2020-06-01 12:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20200531093027epcas1p114ae71536b54ddf42882831cceb007c9@epcas1p1.samsung.com>
2020-05-31  9:30 ` [PATCH 3/4 v4] exfat: add boot region verification Tetsuhiro Kohada
2020-06-01 12:21   ` Sungjong Seo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).