mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
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: ca06197382
("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>
This commit is contained in:
parent
839a534f1e
commit
1e5654de0f
@ -63,7 +63,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_dentries;
|
||||
sector_t sector;
|
||||
struct exfat_chain dir, clu;
|
||||
struct exfat_uni_name uni_name;
|
||||
@ -86,6 +86,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
|
||||
|
||||
dentries_per_clu = sbi->dentries_per_clu;
|
||||
dentries_per_clu_bits = ilog2(dentries_per_clu);
|
||||
max_dentries = (unsigned int)min_t(u64, MAX_EXFAT_DENTRIES,
|
||||
(u64)sbi->num_clusters << dentries_per_clu_bits);
|
||||
|
||||
clu_offset = dentry >> dentries_per_clu_bits;
|
||||
exfat_chain_dup(&clu, &dir);
|
||||
@ -109,7 +111,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
|
||||
}
|
||||
}
|
||||
|
||||
while (clu.dir != EXFAT_EOF_CLUSTER) {
|
||||
while (clu.dir != EXFAT_EOF_CLUSTER && dentry < max_dentries) {
|
||||
i = dentry & (dentries_per_clu - 1);
|
||||
|
||||
for ( ; i < dentries_per_clu; i++, dentry++) {
|
||||
@ -245,7 +247,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);
|
||||
|
Loading…
Reference in New Issue
Block a user