Skip to content

Commit

Permalink
exfat: handle wrong stream entry size in exfat_readdir()
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
namjaejeon committed Jun 4, 2021
1 parent a52427b commit 436aec7
Showing 1 changed file with 7 additions and 2 deletions.
9 changes: 7 additions & 2 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry)
{
int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext;
unsigned int type, clu_offset;
unsigned int type, clu_offset, max_dir_clu;
sector_t sector;
struct exfat_chain dir, clu;
struct exfat_uni_name uni_name;
Expand All @@ -89,6 +89,11 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
dentries_per_clu_bits = ilog2(dentries_per_clu);

clu_offset = dentry >> dentries_per_clu_bits;
max_dir_clu = min_t(unsigned int, MAX_EXFAT_DENTRIES >> dentries_per_clu_bits,
sbi->num_clusters);
if (clu_offset > max_dir_clu)
return 0;

exfat_chain_dup(&clu, &dir);

if (clu.flags == ALLOC_NO_FAT_CHAIN) {
Expand Down Expand Up @@ -246,7 +251,7 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
if (err)
goto unlock;
get_new:
if (cpos >= i_size_read(inode))
if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode))
goto end_of_dir;

err = exfat_readdir(inode, &cpos, &de);
Expand Down

0 comments on commit 436aec7

Please sign in to comment.