Skip to content

Commit 5c0f4cc

Browse files
LiBaokun96tytso
authored andcommitted
ext4: drop ppath from ext4_ext_replay_update_ex() to avoid double-free
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: stable@kernel.org Signed-off-by: Baokun Li <libaokun1@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com> Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com> Link: https://patch.msgid.link/20240822023545.1994557-8-libaokun@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent a164f3a commit 5c0f4cc

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
@@ -5885,7 +5885,7 @@ int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu)
58855885
int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start,
58865886
int len, int unwritten, ext4_fsblk_t pblk)
58875887
{
5888-
struct ext4_ext_path *path = NULL, *ppath;
5888+
struct ext4_ext_path *path;
58895889
struct ext4_extent *ex;
58905890
int ret;
58915891

@@ -5901,30 +5901,29 @@ int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start,
59015901
if (le32_to_cpu(ex->ee_block) != start ||
59025902
ext4_ext_get_actual_len(ex) != len) {
59035903
/* We need to split this extent to match our extent first */
5904-
ppath = path;
59055904
down_write(&EXT4_I(inode)->i_data_sem);
5906-
ret = ext4_force_split_extent_at(NULL, inode, &ppath, start, 1);
5905+
ret = ext4_force_split_extent_at(NULL, inode, &path, start, 1);
59075906
up_write(&EXT4_I(inode)->i_data_sem);
59085907
if (ret)
59095908
goto out;
5910-
kfree(path);
5911-
path = ext4_find_extent(inode, start, NULL, 0);
5909+
5910+
path = ext4_find_extent(inode, start, &path, 0);
59125911
if (IS_ERR(path))
5913-
return -1;
5914-
ppath = path;
5912+
return PTR_ERR(path);
59155913
ex = path[path->p_depth].p_ext;
59165914
WARN_ON(le32_to_cpu(ex->ee_block) != start);
5915+
59175916
if (ext4_ext_get_actual_len(ex) != len) {
59185917
down_write(&EXT4_I(inode)->i_data_sem);
5919-
ret = ext4_force_split_extent_at(NULL, inode, &ppath,
5918+
ret = ext4_force_split_extent_at(NULL, inode, &path,
59205919
start + len, 1);
59215920
up_write(&EXT4_I(inode)->i_data_sem);
59225921
if (ret)
59235922
goto out;
5924-
kfree(path);
5925-
path = ext4_find_extent(inode, start, NULL, 0);
5923+
5924+
path = ext4_find_extent(inode, start, &path, 0);
59265925
if (IS_ERR(path))
5927-
return -EINVAL;
5926+
return PTR_ERR(path);
59285927
ex = path[path->p_depth].p_ext;
59295928
}
59305929
}

0 commit comments

Comments
 (0)