Add checksum validation for dir-entry set when getting it. exfat_calc_entry_set_chksum_with() also validates entry-type. ** This patch depends on: '[PATCH v3] exfat: integrates dir-entry getting and validation' Signed-off-by: Tetsuhiro Kohada <kohada.t2@xxxxxxxxx> --- Changes in v2 - Add error log if checksum mismatch fs/exfat/dir.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index 0b42544e6340..6f9de364a919 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -565,18 +565,27 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, return 0; } -void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es) +static int exfat_calc_entry_set_chksum(struct exfat_entry_set_cache *es, u16 *chksum) { - int chksum_type = CS_DIR_ENTRY, i; - unsigned short chksum = 0; struct exfat_dentry *ep; + int i; - for (i = 0; i < es->num_entries; i++) { - ep = exfat_get_validated_dentry(es, i, TYPE_ALL); - chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum, - chksum_type); - chksum_type = CS_DEFAULT; + ep = container_of(es->de_file, struct exfat_dentry, dentry.file); + *chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, 0, CS_DIR_ENTRY); + for (i = 0; i < es->de_file->num_ext; i++) { + ep = exfat_get_validated_dentry(es, 1 + i, TYPE_SECONDARY); + if (!ep) + return -EIO; + *chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, *chksum, CS_DEFAULT); } + return 0; +} + +void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es) +{ + u16 chksum; + + exfat_calc_entry_set_chksum(es, &chksum); es->de_file->checksum = cpu_to_le16(chksum); es->modified = true; } @@ -777,6 +786,7 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, struct exfat_entry_set_cache *es; struct exfat_dentry *ep; struct buffer_head *bh; + u16 chksum; if (p_dir->dir == DIR_DELETED) { exfat_err(sb, "access to deleted dentry"); @@ -841,11 +851,13 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, goto free_es; es->de_stream = &ep->dentry.stream; - for (i = 2; i < es->num_entries; i++) { - if (!exfat_get_validated_dentry(es, i, TYPE_SECONDARY)) - goto free_es; + if (max_entries == ES_ALL_ENTRIES && + ((exfat_calc_entry_set_chksum(es, &chksum) || + chksum != le16_to_cpu(es->de_file->checksum)))) { + exfat_err(sb, "invalid entry-set checksum (entry : 0x%08x, set-checksum : 0x%04x, checksum : 0x%04x)", + entry, le16_to_cpu(es->de_file->checksum), chksum); + goto free_es; } - return es; free_es: -- 2.25.1