Re: [syzbot] [integrity?] [lsm?] INFO: task hung in process_measurement (2)
From: Yuezhang.Mo@xxxxxxxx
Date: Tue Dec 10 2024 - 21:16:14 EST
#syz testFrom c459223367da6df65ea254059424a86d8d2bf4f8 Mon Sep 17 00:00:00 2001
From: Yuezhang Mo <Yuezhang.Mo@xxxxxxxx>
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 <Yuezhang.Mo@xxxxxxxx>
---
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