[PATCH v2 00/25] ext4: some bugfixes and cleanups for ext4 extents path

libaokun
2024-08-22T02:40:34Z

Hi all!

This patch series is a hardening of ext4 extents path related code.

This is the second version of this patch series. Thank you, Jan Kara and
Ojaswin Mujoo, for the feedback in the previous version. The new version
has no functional changes compared to the previous one, so I've kept the
previous Reviewed-by, please let me know if you have any objections.

The following is a brief overview of the patches, see the patches for
more details.

Patch 1-2: Refactor ext4_ext_rm_idx() as suggested by Jan, and add
appropriate error handling branches to ext4_ext_rm_idx() and
ext4_ext_correct_indexes() to avoid inconsistent extents tree.
PS: This comes from the previous work of my colleague zhanchengbin
(see link), who is no longer in charge of these and I have taken over.
Link: https://lore.kernel.org/r/20230213080514.535568-3-zhanchengbin1@huawei.com/

Patch 3-7: Quick fixes for use-after-free and double-free problems caused
by mixing path(pointer to an extent path) and ppath(pointer to an extent
path pointer).

Patch 8-9: Fix an issue that caused p_bh to be released twice if it wasn't
set to NULL after path->p_bh was released. And add a helper function after
the quick fix to prevent this from happening again.

Patch 10: Fix an issue where the error returned by ext4_find_extent in
ext4_insert_range() was not propagated correctly.

Patch 11-22: Now the use of path and ppath is so confusing that we can
trigger use-after-free or double-free by accessing a stale pointer, or
we can get a memory leak by forgetting to update ppath. And it's very
difficult to read the code. So to make the code more readable, get rid
of ppath and pass path between functions uniformly to avoid these risks.

Patch 23-24: Reduces the consumption of unnecessary memory operations by
avoiding repetitive allocation and release extents path.

Patch 25：Clean up ext4_ext_create_new_leaf() to reduce some unnecessary
indentation and line breaks.

"kvm-xfstests -c ext4/all -g auto" has been executed with no new failures.
Randomly injecting faults(EIO, ENOMEM, Realloc Path) in ext4_find_extent()
while executing xfstests also did not observe new Oops.

Comments and questions are, as always, welcome.
Please let me know what you think.

Thanks,
Baokun

Changes since v1:
* Collect RVB from Honza and Ojaswin.(Thanks for your review!)
* Patch 5: A quick fix has been added for a null pointer or memory leak
that could be caused by ppath remaining NULL when path is reallocated.
* Patch 6: Added a quick fix for the UAF that could be caused by a path
not being updated when the ppath is reallocated.(Spotted by Ojaswin)
* Patch 8: Correct the trace stack in commit message.(Spotted by Ojaswin)
* Patch 10: Quick fixes split from Patch 15 to be easily pulled into
stable.(Suggested by Honza)
* Patch 23: A refactoring split from Patch 16 for easy review.(Suggested
by Ojaswin)
* Patch 24: Modify the patch subject.
* Patch 25: Added cleanup patch to remove unnecessary indentation and
line breaks in ext4_ext_create_new_leaf().(Suggested by Honza)
* Adjust the sequence of patches.

v1: https://lore.kernel.org/r/20240710040654.1714672-1-libaokun@huaweicloud.com

Baokun Li (25):
ext4: refactor ext4_ext_rm_idx() to index 'path'
ext4: prevent partial update of the extents path
ext4: fix slab-use-after-free in ext4_split_extent_at()
ext4: avoid use-after-free in ext4_ext_show_leaf()
ext4: update orig_path in ext4_find_extent()
ext4: aovid use-after-free in ext4_ext_insert_extent()
ext4: drop ppath from ext4_ext_replay_update_ex() to avoid double-free
ext4: fix double brelse() the buffer of the extents path
ext4: add new ext4_ext_path_brelse() helper
ext4: propagate errors from ext4_find_extent() in ext4_insert_range()
ext4: get rid of ppath in ext4_find_extent()
ext4: get rid of ppath in get_ext_path()
ext4: get rid of ppath in ext4_ext_create_new_leaf()
ext4: get rid of ppath in ext4_ext_insert_extent()
ext4: get rid of ppath in ext4_split_extent_at()
ext4: get rid of ppath in ext4_force_split_extent_at()
ext4: get rid of ppath in ext4_split_extent()
ext4: get rid of ppath in ext4_split_convert_extents()
ext4: get rid of ppath in ext4_convert_unwritten_extents_endio()
ext4: get rid of ppath in ext4_ext_convert_to_initialized()
ext4: get rid of ppath in ext4_ext_handle_unwritten_extents()
ext4: get rid of ppath in convert_initialized_extent()
ext4: refactor ext4_swap_extents() to reuse extents path
ext4: make some fast commit functions reuse extents path
ext4: save unnecessary indentation in ext4_ext_create_new_leaf()

fs/ext4/ext4.h | 9 +-
fs/ext4/extents.c | 781 +++++++++++++++++++++++-------------------
fs/ext4/fast_commit.c | 17 +-
fs/ext4/migrate.c | 5 +-
fs/ext4/move_extent.c | 36 +-
5 files changed, 456 insertions(+), 392 deletions(-)

--
2.39.2