| From d7dce9e08595e80bf8039a81794809c66fe26431 Mon Sep 17 00:00:00 2001 |
| From: yangerkun <yangerkun@huawei.com> |
| Date: Wed, 28 Oct 2020 13:56:17 +0800 |
| Subject: ext4: do not use extent after put_bh |
| |
| From: yangerkun <yangerkun@huawei.com> |
| |
| commit d7dce9e08595e80bf8039a81794809c66fe26431 upstream. |
| |
| ext4_ext_search_right() will read more extent blocks and call put_bh |
| after we get the information we need. However, ret_ex will break this |
| and may cause use-after-free once pagecache has been freed. Fix it by |
| copying the extent structure if needed. |
| |
| Signed-off-by: yangerkun <yangerkun@huawei.com> |
| Link: https://lore.kernel.org/r/20201028055617.2569255-1-yangerkun@huawei.com |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Cc: stable@kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ext4/extents.c | 30 +++++++++++++++--------------- |
| 1 file changed, 15 insertions(+), 15 deletions(-) |
| |
| --- a/fs/ext4/extents.c |
| +++ b/fs/ext4/extents.c |
| @@ -1472,16 +1472,16 @@ static int ext4_ext_search_left(struct i |
| } |
| |
| /* |
| - * search the closest allocated block to the right for *logical |
| - * and returns it at @logical + it's physical address at @phys |
| - * if *logical is the largest allocated block, the function |
| - * returns 0 at @phys |
| - * return value contains 0 (success) or error code |
| + * Search the closest allocated block to the right for *logical |
| + * and returns it at @logical + it's physical address at @phys. |
| + * If not exists, return 0 and @phys is set to 0. We will return |
| + * 1 which means we found an allocated block and ret_ex is valid. |
| + * Or return a (< 0) error code. |
| */ |
| static int ext4_ext_search_right(struct inode *inode, |
| struct ext4_ext_path *path, |
| ext4_lblk_t *logical, ext4_fsblk_t *phys, |
| - struct ext4_extent **ret_ex) |
| + struct ext4_extent *ret_ex) |
| { |
| struct buffer_head *bh = NULL; |
| struct ext4_extent_header *eh; |
| @@ -1575,10 +1575,11 @@ got_index: |
| found_extent: |
| *logical = le32_to_cpu(ex->ee_block); |
| *phys = ext4_ext_pblock(ex); |
| - *ret_ex = ex; |
| + if (ret_ex) |
| + *ret_ex = *ex; |
| if (bh) |
| put_bh(bh); |
| - return 0; |
| + return 1; |
| } |
| |
| /* |
| @@ -2869,8 +2870,8 @@ again: |
| */ |
| lblk = ex_end + 1; |
| err = ext4_ext_search_right(inode, path, &lblk, &pblk, |
| - &ex); |
| - if (err) |
| + NULL); |
| + if (err < 0) |
| goto out; |
| if (pblk) { |
| partial.pclu = EXT4_B2C(sbi, pblk); |
| @@ -4038,7 +4039,7 @@ int ext4_ext_map_blocks(handle_t *handle |
| struct ext4_map_blocks *map, int flags) |
| { |
| struct ext4_ext_path *path = NULL; |
| - struct ext4_extent newex, *ex, *ex2; |
| + struct ext4_extent newex, *ex, ex2; |
| struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
| ext4_fsblk_t newblock = 0, pblk; |
| int err = 0, depth, ret; |
| @@ -4174,15 +4175,14 @@ int ext4_ext_map_blocks(handle_t *handle |
| if (err) |
| goto out; |
| ar.lright = map->m_lblk; |
| - ex2 = NULL; |
| err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright, &ex2); |
| - if (err) |
| + if (err < 0) |
| goto out; |
| |
| /* Check if the extent after searching to the right implies a |
| * cluster we can use. */ |
| - if ((sbi->s_cluster_ratio > 1) && ex2 && |
| - get_implied_cluster_alloc(inode->i_sb, map, ex2, path)) { |
| + if ((sbi->s_cluster_ratio > 1) && err && |
| + get_implied_cluster_alloc(inode->i_sb, map, &ex2, path)) { |
| ar.len = allocated = map->m_len; |
| newblock = map->m_pblk; |
| goto got_allocated_blocks; |