Skip to content

Commit 79c1587

Browse files
committed
exfat: validate cluster allocation bits of the allocation bitmap
syzbot created an exfat image with cluster bits not set for the allocation bitmap. exfat-fs reads and uses the allocation bitmap without checking this. The problem is that if the start cluster of the allocation bitmap is 6, cluster 6 can be allocated when creating a directory with mkdir. exfat zeros out this cluster in exfat_mkdir, which can delete existing entries. This can reallocate the allocated entries. In addition, the allocation bitmap is also zeroed out, so cluster 6 can be reallocated. This patch adds exfat_test_bitmap_range to validate that clusters used for the allocation bitmap are correctly marked as in-use. Reported-by: [email protected] Tested-by: [email protected] Reviewed-by: Yuezhang Mo <[email protected]> Reviewed-by: Sungjong Seo <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent 6dfba10 commit 79c1587

File tree

1 file changed

+60
-12
lines changed

1 file changed

+60
-12
lines changed

fs/exfat/balloc.c

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,55 @@
2626
/*
2727
* Allocation Bitmap Management Functions
2828
*/
29+
static bool exfat_test_bitmap_range(struct super_block *sb, unsigned int clu,
30+
unsigned int count)
31+
{
32+
struct exfat_sb_info *sbi = EXFAT_SB(sb);
33+
unsigned int start = clu;
34+
unsigned int end = clu + count;
35+
unsigned int ent_idx, i, b;
36+
unsigned int bit_offset, bits_to_check;
37+
__le_long *bitmap_le;
38+
unsigned long mask, word;
39+
40+
if (!is_valid_cluster(sbi, start) || !is_valid_cluster(sbi, end - 1))
41+
return false;
42+
43+
while (start < end) {
44+
ent_idx = CLUSTER_TO_BITMAP_ENT(start);
45+
i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
46+
b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
47+
48+
bitmap_le = (__le_long *)sbi->vol_amap[i]->b_data;
49+
50+
/* Calculate how many bits we can check in the current word */
51+
bit_offset = b % BITS_PER_LONG;
52+
bits_to_check = min(end - start,
53+
(unsigned int)(BITS_PER_LONG - bit_offset));
54+
55+
/* Create a bitmask for the range of bits to check */
56+
if (bits_to_check >= BITS_PER_LONG)
57+
mask = ~0UL;
58+
else
59+
mask = ((1UL << bits_to_check) - 1) << bit_offset;
60+
word = lel_to_cpu(bitmap_le[b / BITS_PER_LONG]);
61+
62+
/* Check if all bits in the mask are set */
63+
if ((word & mask) != mask)
64+
return false;
65+
66+
start += bits_to_check;
67+
}
68+
69+
return true;
70+
}
71+
2972
static int exfat_allocate_bitmap(struct super_block *sb,
3073
struct exfat_dentry *ep)
3174
{
3275
struct exfat_sb_info *sbi = EXFAT_SB(sb);
3376
long long map_size;
34-
unsigned int i, need_map_size;
77+
unsigned int i, j, need_map_size;
3578
sector_t sector;
3679

3780
sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu);
@@ -58,20 +101,25 @@ static int exfat_allocate_bitmap(struct super_block *sb,
58101
sector = exfat_cluster_to_sector(sbi, sbi->map_clu);
59102
for (i = 0; i < sbi->map_sectors; i++) {
60103
sbi->vol_amap[i] = sb_bread(sb, sector + i);
61-
if (!sbi->vol_amap[i]) {
62-
/* release all buffers and free vol_amap */
63-
int j = 0;
64-
65-
while (j < i)
66-
brelse(sbi->vol_amap[j++]);
67-
68-
kvfree(sbi->vol_amap);
69-
sbi->vol_amap = NULL;
70-
return -EIO;
71-
}
104+
if (!sbi->vol_amap[i])
105+
goto err_out;
72106
}
73107

108+
if (exfat_test_bitmap_range(sb, sbi->map_clu,
109+
EXFAT_B_TO_CLU_ROUND_UP(map_size, sbi)) == false)
110+
goto err_out;
111+
74112
return 0;
113+
114+
err_out:
115+
j = 0;
116+
/* release all buffers and free vol_amap */
117+
while (j < i)
118+
brelse(sbi->vol_amap[j++]);
119+
120+
kvfree(sbi->vol_amap);
121+
sbi->vol_amap = NULL;
122+
return -EIO;
75123
}
76124

77125
int exfat_load_bitmap(struct super_block *sb)

0 commit comments

Comments
 (0)