Commit 476189c0 authored by Tetsuhiro Kohada's avatar Tetsuhiro Kohada Committed by Namjae Jeon
Browse files

exfat: add boot region verification



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: default avatarTetsuhiro Kohada <kohada.t2@gmail.com>
Reviewed-by: default avatarSungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: default avatarNamjae Jeon <namjae.jeon@samsung.com>
parent 33404a15
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+14 −0
Original line number Diff line number Diff line
@@ -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);
+50 −0
Original line number Diff line number Diff line
@@ -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");