diff options
author | Theodore Ts'o <tytso@mit.edu> | 2018-03-26 23:54:10 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2018-03-26 23:54:10 -0400 |
commit | 7dac4a1726a9c64a517d595c40e95e2d0d135f6f (patch) | |
tree | c750d6e29407cc63499a6659abc2c45635a4bf28 | |
parent | dcae058a8da9c3cfc0055c7937ccd1a3dd0382a8 (diff) |
ext4: add validity checks for bitmap block numbers
An privileged attacker can cause a crash by mounting a crafted ext4
image which triggers a out-of-bounds read in the function
ext4_valid_block_bitmap() in fs/ext4/balloc.c.
This issue has been assigned CVE-2018-1093.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199181
BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1560782
Reported-by: Wen Xu <wen.xu@gatech.edu>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@vger.kernel.org
-rw-r--r-- | fs/ext4/balloc.c | 16 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 7 |
2 files changed, 21 insertions, 2 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index f82c4966f4ce..a33d8fb1bf2a 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -338,20 +338,25 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, | |||
338 | /* check whether block bitmap block number is set */ | 338 | /* check whether block bitmap block number is set */ |
339 | blk = ext4_block_bitmap(sb, desc); | 339 | blk = ext4_block_bitmap(sb, desc); |
340 | offset = blk - group_first_block; | 340 | offset = blk - group_first_block; |
341 | if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) | 341 | if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || |
342 | !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) | ||
342 | /* bad block bitmap */ | 343 | /* bad block bitmap */ |
343 | return blk; | 344 | return blk; |
344 | 345 | ||
345 | /* check whether the inode bitmap block number is set */ | 346 | /* check whether the inode bitmap block number is set */ |
346 | blk = ext4_inode_bitmap(sb, desc); | 347 | blk = ext4_inode_bitmap(sb, desc); |
347 | offset = blk - group_first_block; | 348 | offset = blk - group_first_block; |
348 | if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) | 349 | if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || |
350 | !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) | ||
349 | /* bad block bitmap */ | 351 | /* bad block bitmap */ |
350 | return blk; | 352 | return blk; |
351 | 353 | ||
352 | /* check whether the inode table block number is set */ | 354 | /* check whether the inode table block number is set */ |
353 | blk = ext4_inode_table(sb, desc); | 355 | blk = ext4_inode_table(sb, desc); |
354 | offset = blk - group_first_block; | 356 | offset = blk - group_first_block; |
357 | if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || | ||
358 | EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= sb->s_blocksize) | ||
359 | return blk; | ||
355 | next_zero_bit = ext4_find_next_zero_bit(bh->b_data, | 360 | next_zero_bit = ext4_find_next_zero_bit(bh->b_data, |
356 | EXT4_B2C(sbi, offset + sbi->s_itb_per_group), | 361 | EXT4_B2C(sbi, offset + sbi->s_itb_per_group), |
357 | EXT4_B2C(sbi, offset)); | 362 | EXT4_B2C(sbi, offset)); |
@@ -417,6 +422,7 @@ struct buffer_head * | |||
417 | ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | 422 | ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) |
418 | { | 423 | { |
419 | struct ext4_group_desc *desc; | 424 | struct ext4_group_desc *desc; |
425 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
420 | struct buffer_head *bh; | 426 | struct buffer_head *bh; |
421 | ext4_fsblk_t bitmap_blk; | 427 | ext4_fsblk_t bitmap_blk; |
422 | int err; | 428 | int err; |
@@ -425,6 +431,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | |||
425 | if (!desc) | 431 | if (!desc) |
426 | return ERR_PTR(-EFSCORRUPTED); | 432 | return ERR_PTR(-EFSCORRUPTED); |
427 | bitmap_blk = ext4_block_bitmap(sb, desc); | 433 | bitmap_blk = ext4_block_bitmap(sb, desc); |
434 | if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || | ||
435 | (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { | ||
436 | ext4_error(sb, "Invalid block bitmap block %llu in " | ||
437 | "block_group %u", bitmap_blk, block_group); | ||
438 | return ERR_PTR(-EFSCORRUPTED); | ||
439 | } | ||
428 | bh = sb_getblk(sb, bitmap_blk); | 440 | bh = sb_getblk(sb, bitmap_blk); |
429 | if (unlikely(!bh)) { | 441 | if (unlikely(!bh)) { |
430 | ext4_error(sb, "Cannot get buffer for block bitmap - " | 442 | ext4_error(sb, "Cannot get buffer for block bitmap - " |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 3fa93665b4a3..df92e3ec9913 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -122,6 +122,7 @@ static struct buffer_head * | |||
122 | ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | 122 | ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) |
123 | { | 123 | { |
124 | struct ext4_group_desc *desc; | 124 | struct ext4_group_desc *desc; |
125 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
125 | struct buffer_head *bh = NULL; | 126 | struct buffer_head *bh = NULL; |
126 | ext4_fsblk_t bitmap_blk; | 127 | ext4_fsblk_t bitmap_blk; |
127 | int err; | 128 | int err; |
@@ -131,6 +132,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
131 | return ERR_PTR(-EFSCORRUPTED); | 132 | return ERR_PTR(-EFSCORRUPTED); |
132 | 133 | ||
133 | bitmap_blk = ext4_inode_bitmap(sb, desc); | 134 | bitmap_blk = ext4_inode_bitmap(sb, desc); |
135 | if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || | ||
136 | (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { | ||
137 | ext4_error(sb, "Invalid inode bitmap blk %llu in " | ||
138 | "block_group %u", bitmap_blk, block_group); | ||
139 | return ERR_PTR(-EFSCORRUPTED); | ||
140 | } | ||
134 | bh = sb_getblk(sb, bitmap_blk); | 141 | bh = sb_getblk(sb, bitmap_blk); |
135 | if (unlikely(!bh)) { | 142 | if (unlikely(!bh)) { |
136 | ext4_error(sb, "Cannot read inode bitmap - " | 143 | ext4_error(sb, "Cannot read inode bitmap - " |