Skip to content

Commit 436aec7

Browse files
committed
exfat: handle wrong stream entry size in exfat_readdir()
The compatibility between linux exfat and exfat of some camera company was reported as a problem. In their exfat, if the number of files exceeds any limit, the DataLength in stream entry of the directory is not updated. There is a problem that some files created from camera does not show in linux exfat. In linux exfat, if cpos becomes larger than stream entry size, there is a check not to call exfat_readdir(). This patch check stream entry size only if it is ALLOC_NO_FAT_CHAIN and add the check ensure that the number of dentry does not exceed max dentries size(256 MB) to prevent the circular FAT chain issue. Reported-by: Florian Cramer <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent a52427b commit 436aec7

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

dir.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
6464
static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry)
6565
{
6666
int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext;
67-
unsigned int type, clu_offset;
67+
unsigned int type, clu_offset, max_dir_clu;
6868
sector_t sector;
6969
struct exfat_chain dir, clu;
7070
struct exfat_uni_name uni_name;
@@ -89,6 +89,11 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
8989
dentries_per_clu_bits = ilog2(dentries_per_clu);
9090

9191
clu_offset = dentry >> dentries_per_clu_bits;
92+
max_dir_clu = min_t(unsigned int, MAX_EXFAT_DENTRIES >> dentries_per_clu_bits,
93+
sbi->num_clusters);
94+
if (clu_offset > max_dir_clu)
95+
return 0;
96+
9297
exfat_chain_dup(&clu, &dir);
9398

9499
if (clu.flags == ALLOC_NO_FAT_CHAIN) {
@@ -246,7 +251,7 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
246251
if (err)
247252
goto unlock;
248253
get_new:
249-
if (cpos >= i_size_read(inode))
254+
if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode))
250255
goto end_of_dir;
251256

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

0 commit comments

Comments
 (0)