From e75c5725762dddfe5b618f8ef9e8ac884d8d66bd Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 8 Nov 2025 20:04:04 +0900 Subject: [PATCH] exfat: validate the cluster bitmap bits of root directory Syzbot created this issue by testing an image that did not have the root cluster bitmap bit marked. After accessing a file through the root directory via exfat_lookup, when creating a file again with mkdir, the root cluster bit can be allocated for direcotry, which can cause the root cluster to be zeroed out and the same entry can be allocated in the same cluster. This patch improved this issue by adding exfat_test_bitmap to check the cluster bit and validate the clusters of the root directory. Signed-off-by: Namjae Jeon --- fs/exfat/balloc.c | 19 +++++++++++++++++++ fs/exfat/exfat_fs.h | 1 + fs/exfat/super.c | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c index 2d2d510f2372..e6d5b9cb56d6 100644 --- a/fs/exfat/balloc.c +++ b/fs/exfat/balloc.c @@ -24,6 +24,25 @@ #error "BITS_PER_LONG not 32 or 64" #endif +bool exfat_test_bitmap(struct super_block *sb, unsigned int clu) +{ + int i, b; + unsigned int ent_idx; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + if (!is_valid_cluster(sbi, clu)) + return false; + + ent_idx = CLUSTER_TO_BITMAP_ENT(clu); + i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); + b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); + + if (!test_bit_le(b, sbi->vol_amap[i]->b_data)) + return false; + + return true; +} + /* * Allocation Bitmap Management Functions */ diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index 38210fb6901c..6a317917506c 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -450,6 +450,7 @@ int exfat_count_num_clusters(struct super_block *sb, struct exfat_chain *p_chain, unsigned int *ret_count); /* balloc.c */ +bool exfat_test_bitmap(struct super_block *sb, unsigned int clu); 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); diff --git a/fs/exfat/super.c b/fs/exfat/super.c index 7f9592856bf7..ce05dc604e13 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -626,6 +626,12 @@ static int __exfat_fill_super(struct super_block *sb, goto free_bh; } + if (!exfat_test_bitmap(sb, sbi->root_dir)) { + exfat_err(sb, "failed to test root cluster bit"); + ret = -EIO; + goto free_alloc_bitmap; + } + ret = exfat_count_used_clusters(sb, &sbi->used_clusters); if (ret) { exfat_err(sb, "failed to scan clusters"); -- 2.25.1