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

Reply via email to