Skip to content

Commit

Permalink
ext4: do not use extent after put_bh
Browse files Browse the repository at this point in the history
commit d7dce9e 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>
  • Loading branch information
yangerkun authored and gregkh committed Nov 5, 2020
1 parent 7bb9a23 commit cef20b4
Showing 1 changed file with 15 additions and 15 deletions.
30 changes: 15 additions & 15 deletions fs/ext4/extents.c
Expand Up @@ -1472,16 +1472,16 @@ static int ext4_ext_search_left(struct inode *inode,
}

/*
* 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;
Expand Down Expand Up @@ -1575,10 +1575,11 @@ static int ext4_ext_search_right(struct inode *inode,
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;
}

/*
Expand Down Expand Up @@ -2869,8 +2870,8 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
*/
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);
Expand Down Expand Up @@ -4038,7 +4039,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
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;
Expand Down Expand Up @@ -4174,15 +4175,14 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
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;
Expand Down

0 comments on commit cef20b4

Please sign in to comment.