Blame SOURCES/0077-exfat-handle-wrong-stream-entry-size-in-exfat_readdi.patch

Kmods SIG 50e2b3
From 1e5654de0f51890f88abd409ebf4867782431e81 Mon Sep 17 00:00:00 2001
Kmods SIG 50e2b3
From: Namjae Jeon <namjae.jeon@samsung.com>
Kmods SIG 50e2b3
Date: Fri, 11 Jun 2021 09:40:24 +0900
Kmods SIG 50e2b3
Subject: [Backport 1e5654de0f51] exfat: handle wrong stream entry size in
Kmods SIG 50e2b3
 exfat_readdir()
Kmods SIG 50e2b3
Kmods SIG 50e2b3
The compatibility issue between linux exfat and exfat of some camera
Kmods SIG 50e2b3
company was reported from Florian. In their exfat, if the number of files
Kmods SIG 50e2b3
exceeds any limit, the DataLength in stream entry of the directory is
Kmods SIG 50e2b3
no longer updated. So some files created from camera does not show in
Kmods SIG 50e2b3
linux exfat. because linux exfat doesn't allow that cpos becomes larger
Kmods SIG 50e2b3
than DataLength of stream entry. This patch check DataLength in stream
Kmods SIG 50e2b3
entry only if the type is ALLOC_NO_FAT_CHAIN and add the check ensure
Kmods SIG 50e2b3
that dentry offset does not exceed max dentries size(256 MB) to avoid
Kmods SIG 50e2b3
the circular FAT chain issue.
Kmods SIG 50e2b3
Kmods SIG 50e2b3
Fixes: ca06197382bd ("exfat: add directory operations")
Kmods SIG 50e2b3
Cc: stable@vger.kernel.org # v5.9
Kmods SIG 50e2b3
Reported-by: Florian Cramer <flrncrmr@gmail.com>
Kmods SIG 50e2b3
Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
Kmods SIG 50e2b3
Tested-by: Chris Down <chris@chrisdown.name>
Kmods SIG 50e2b3
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Kmods SIG 50e2b3
---
Kmods SIG 50e2b3
 src/dir.c | 8 +++++---
Kmods SIG 50e2b3
 1 file changed, 5 insertions(+), 3 deletions(-)
Kmods SIG 50e2b3
Kmods SIG 50e2b3
diff --git a/src/dir.c b/src/dir.c
Kmods SIG 50e2b3
index c4523648472a088a2477ea9c3ffe7416c498b523..cb1c0d8c17141b1a0b1fdb70167cce3ec3c5446b 100644
Kmods SIG 50e2b3
--- a/src/dir.c
Kmods SIG 50e2b3
+++ b/src/dir.c
Kmods SIG 50e2b3
@@ -63,7 +63,7 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
Kmods SIG 50e2b3
 static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry)
Kmods SIG 50e2b3
 {
Kmods SIG 50e2b3
 	int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext;
Kmods SIG 50e2b3
-	unsigned int type, clu_offset;
Kmods SIG 50e2b3
+	unsigned int type, clu_offset, max_dentries;
Kmods SIG 50e2b3
 	sector_t sector;
Kmods SIG 50e2b3
 	struct exfat_chain dir, clu;
Kmods SIG 50e2b3
 	struct exfat_uni_name uni_name;
Kmods SIG 50e2b3
@@ -86,6 +86,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 	dentries_per_clu = sbi->dentries_per_clu;
Kmods SIG 50e2b3
 	dentries_per_clu_bits = ilog2(dentries_per_clu);
Kmods SIG 50e2b3
+	max_dentries = (unsigned int)min_t(u64, MAX_EXFAT_DENTRIES,
Kmods SIG 50e2b3
+					   (u64)sbi->num_clusters << dentries_per_clu_bits);
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 	clu_offset = dentry >> dentries_per_clu_bits;
Kmods SIG 50e2b3
 	exfat_chain_dup(&clu, &dir;;
Kmods SIG 50e2b3
@@ -109,7 +111,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
Kmods SIG 50e2b3
 		}
Kmods SIG 50e2b3
 	}
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
-	while (clu.dir != EXFAT_EOF_CLUSTER) {
Kmods SIG 50e2b3
+	while (clu.dir != EXFAT_EOF_CLUSTER && dentry < max_dentries) {
Kmods SIG 50e2b3
 		i = dentry & (dentries_per_clu - 1);
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 		for ( ; i < dentries_per_clu; i++, dentry++) {
Kmods SIG 50e2b3
@@ -245,7 +247,7 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
Kmods SIG 50e2b3
 	if (err)
Kmods SIG 50e2b3
 		goto unlock;
Kmods SIG 50e2b3
 get_new:
Kmods SIG 50e2b3
-	if (cpos >= i_size_read(inode))
Kmods SIG 50e2b3
+	if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode))
Kmods SIG 50e2b3
 		goto end_of_dir;
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 	err = exfat_readdir(inode, &cpos, &de);
Kmods SIG 50e2b3
-- 
Kmods SIG 50e2b3
2.31.1
Kmods SIG 50e2b3