lkml.org 
[lkml]   [2020]   [Nov]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.9 348/391] ext4: do not use extent after put_bh
    Date
    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;

    \
     
     \ /
      Last update: 2020-11-03 22:46    [W:4.117 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site