Add checksum validation for dir-entry set when getting it. exfat_calc_entry_set_chksum_with() also validates entry-type. Signed-off-by: Tetsuhiro Kohada <kohada.t2@xxxxxxxxx> --- Changes in v2 - Add error log if checksum mismatch Changes in v3: - Nothing Changes in v4: - Into patch series '[PATCH v4] exfat: integrates dir-entry getting and validation' fs/exfat/dir.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index cd37091844fa..d4beea796708 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -565,18 +565,26 @@ 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; - u16 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; + *chksum = exfat_calc_chksum16(es->ep_file, DENTRY_SIZE, 0, CS_DIR_ENTRY); + for (i = 0; i < ES_FILE(es).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_FILE(es).checksum = cpu_to_le16(chksum); es->modified = true; } @@ -776,6 +784,7 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_entry_set_cache *es; struct buffer_head *bh; + u16 chksum; if (p_dir->dir == DIR_DELETED) { exfat_err(sb, "access to deleted dentry"); @@ -839,9 +848,12 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, goto free_es; if (max_entries == ES_ALL_ENTRIES) { - for (i = 0; i < ES_FILE(es).num_ext; i++) - if (!exfat_get_validated_dentry(es, ES_INDEX_STREAM + i, TYPE_SECONDARY)) - goto free_es; + if (exfat_calc_entry_set_chksum(es, &chksum) || + chksum != le16_to_cpu(ES_FILE(es).checksum)) { + exfat_err(sb, "invalid entry-set checksum (entry : 0x%08x, set-checksum : 0x%04x, checksum : 0x%04x)", + entry, le16_to_cpu(ES_FILE(es).checksum), chksum); + goto free_es; + } for (i = 0; i * EXFAT_FILE_NAME_LEN < ES_STREAM(es).name_len; i++) if (!exfat_get_validated_dentry(es, ES_INDEX_NAME + i, TYPE_NAME)) goto free_es; -- 2.25.1