Skip to content

Commit 6367d3f

Browse files
LiBaokun96gregkh
authored andcommitted
ext4: drop ppath from ext4_ext_replay_update_ex() to avoid double-free
commit 5c0f4cc upstream. When calling ext4_force_split_extent_at() in ext4_ext_replay_update_ex(), the 'ppath' is updated but it is the 'path' that is freed, thus potentially triggering a double-free in the following process: ext4_ext_replay_update_ex ppath = path ext4_force_split_extent_at(&ppath) ext4_split_extent_at ext4_ext_insert_extent ext4_ext_create_new_leaf ext4_ext_grow_indepth ext4_find_extent if (depth > path[0].p_maxdepth) kfree(path) ---> path First freed *orig_path = path = NULL ---> null ppath kfree(path) ---> path double-free !!! So drop the unnecessary ppath and use path directly to avoid this problem. And use ext4_find_extent() directly to update path, avoiding unnecessary memory allocation and freeing. Also, propagate the error returned by ext4_find_extent() instead of using strange error codes. Fixes: 8016e29 ("ext4: fast commit recovery path") Cc: [email protected] Signed-off-by: Baokun Li <[email protected]> Reviewed-by: Jan Kara <[email protected]> Reviewed-by: Ojaswin Mujoo <[email protected]> Tested-by: Ojaswin Mujoo <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Theodore Ts'o <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bd87b99 commit 6367d3f

File tree

1 file changed

+10
-11
lines changed

1 file changed

+10
-11
lines changed

fs/ext4/extents.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5926,7 +5926,7 @@ int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu)
59265926
int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start,
59275927
int len, int unwritten, ext4_fsblk_t pblk)
59285928
{
5929-
struct ext4_ext_path *path = NULL, *ppath;
5929+
struct ext4_ext_path *path;
59305930
struct ext4_extent *ex;
59315931
int ret;
59325932

@@ -5942,30 +5942,29 @@ int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start,
59425942
if (le32_to_cpu(ex->ee_block) != start ||
59435943
ext4_ext_get_actual_len(ex) != len) {
59445944
/* We need to split this extent to match our extent first */
5945-
ppath = path;
59465945
down_write(&EXT4_I(inode)->i_data_sem);
5947-
ret = ext4_force_split_extent_at(NULL, inode, &ppath, start, 1);
5946+
ret = ext4_force_split_extent_at(NULL, inode, &path, start, 1);
59485947
up_write(&EXT4_I(inode)->i_data_sem);
59495948
if (ret)
59505949
goto out;
5951-
kfree(path);
5952-
path = ext4_find_extent(inode, start, NULL, 0);
5950+
5951+
path = ext4_find_extent(inode, start, &path, 0);
59535952
if (IS_ERR(path))
5954-
return -1;
5955-
ppath = path;
5953+
return PTR_ERR(path);
59565954
ex = path[path->p_depth].p_ext;
59575955
WARN_ON(le32_to_cpu(ex->ee_block) != start);
5956+
59585957
if (ext4_ext_get_actual_len(ex) != len) {
59595958
down_write(&EXT4_I(inode)->i_data_sem);
5960-
ret = ext4_force_split_extent_at(NULL, inode, &ppath,
5959+
ret = ext4_force_split_extent_at(NULL, inode, &path,
59615960
start + len, 1);
59625961
up_write(&EXT4_I(inode)->i_data_sem);
59635962
if (ret)
59645963
goto out;
5965-
kfree(path);
5966-
path = ext4_find_extent(inode, start, NULL, 0);
5964+
5965+
path = ext4_find_extent(inode, start, &path, 0);
59675966
if (IS_ERR(path))
5968-
return -EINVAL;
5967+
return PTR_ERR(path);
59695968
ex = path[path->p_depth].p_ext;
59705969
}
59715970
}

0 commit comments

Comments
 (0)