From c459223367da6df65ea254059424a86d8d2bf4f8 Mon Sep 17 00:00:00 2001 From: Yuezhang Mo Date: Tue, 10 Dec 2024 18:02:07 +0800 Subject: [PATCH] exfat: check cluster chain loop when freeing clusters In order to avoid orphan clusters, clusters in the cluster chain need to be freed until the EOF cluster is traversed. However, if a cluster chain includes a loop in itself, the EOF cluster will cannot be traversed, resulting in an infinite loop. Signed-off-by: Yuezhang Mo --- fs/exfat/balloc.c | 13 +++++++++++++ fs/exfat/exfat_fs.h | 1 + fs/exfat/fatent.c | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c index ce9be95c9172..398a05d2a2dd 100644 --- a/fs/exfat/balloc.c +++ b/fs/exfat/balloc.c @@ -173,6 +173,19 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync) } } +bool exfat_test_bitmap(struct super_block *sb, unsigned int clu) +{ + unsigned int map_i, map_b, bit; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + bit = CLUSTER_TO_BITMAP_ENT(clu); + map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, bit); + map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, bit); + bit &= (BITS_PER_BYTE - 1); + + return *(sbi->vol_amap[map_i]->b_data + map_b) & BIT(bit); +} + /* * If the value of "clu" is 0, it means cluster 2 which is the first cluster of * the cluster heap. diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index 78be6964a8a0..90d907609e47 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -457,6 +457,7 @@ int exfat_load_bitmap(struct super_block *sb); void exfat_free_bitmap(struct exfat_sb_info *sbi); int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync); void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync); +bool exfat_test_bitmap(struct super_block *sb, unsigned int clu); unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu); int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count); int exfat_trim_fs(struct inode *inode, struct fstrim_range *range); diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index 56b870d9cc0d..5d8b7413d80d 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -199,6 +199,14 @@ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain unsigned int n_clu = clu; int err = exfat_get_next_cluster(sb, &n_clu); + /* + * To avoid the cluster chain itself including a loop + * causing an infinite loop. + */ + if (num_clusters >= p_chain->size && + !exfat_test_bitmap(sb, clu)) + break; + if (err || n_clu == EXFAT_EOF_CLUSTER) sync = true; else -- 2.43.0