Skip to content

Commit 1e5654d

Browse files
committed
exfat: handle wrong stream entry size in exfat_readdir()
The compatibility issue between linux exfat and exfat of some camera company was reported from Florian. In their exfat, if the number of files exceeds any limit, the DataLength in stream entry of the directory is no longer updated. So some files created from camera does not show in linux exfat. because linux exfat doesn't allow that cpos becomes larger than DataLength of stream entry. This patch check DataLength in stream entry only if the type is ALLOC_NO_FAT_CHAIN and add the check ensure that dentry offset does not exceed max dentries size(256 MB) to avoid the circular FAT chain issue. Fixes: ca06197 ("exfat: add directory operations") Cc: stable@vger.kernel.org # v5.9 Reported-by: Florian Cramer <flrncrmr@gmail.com> Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com> Tested-by: Chris Down <chris@chrisdown.name> Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
1 parent 839a534 commit 1e5654d

1 file changed

Lines changed: 5 additions & 3 deletions

File tree

fs/exfat/dir.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
6363
static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry)
6464
{
6565
int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext;
66-
unsigned int type, clu_offset;
66+
unsigned int type, clu_offset, max_dentries;
6767
sector_t sector;
6868
struct exfat_chain dir, clu;
6969
struct exfat_uni_name uni_name;
@@ -86,6 +86,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
8686

8787
dentries_per_clu = sbi->dentries_per_clu;
8888
dentries_per_clu_bits = ilog2(dentries_per_clu);
89+
max_dentries = (unsigned int)min_t(u64, MAX_EXFAT_DENTRIES,
90+
(u64)sbi->num_clusters << dentries_per_clu_bits);
8991

9092
clu_offset = dentry >> dentries_per_clu_bits;
9193
exfat_chain_dup(&clu, &dir);
@@ -109,7 +111,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
109111
}
110112
}
111113

112-
while (clu.dir != EXFAT_EOF_CLUSTER) {
114+
while (clu.dir != EXFAT_EOF_CLUSTER && dentry < max_dentries) {
113115
i = dentry & (dentries_per_clu - 1);
114116

115117
for ( ; i < dentries_per_clu; i++, dentry++) {
@@ -245,7 +247,7 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
245247
if (err)
246248
goto unlock;
247249
get_new:
248-
if (cpos >= i_size_read(inode))
250+
if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode))
249251
goto end_of_dir;
250252

251253
err = exfat_readdir(inode, &cpos, &de);

0 commit comments

Comments
 (0)