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