On Thu 22-08-24 10:35:25, libaokun@xxxxxxxxxxxxxxx wrote: > From: Baokun Li <libaokun1@xxxxxxxxxx> > > In ext4_find_extent(), if the path is not big enough, we free it and set > *orig_path to NULL. But after reallocating and successfully initializing > the path, we don't update *orig_path, in which case the caller gets a > valid path but a NULL ppath, and this may cause a NULL pointer dereference > or a path memory leak. For example: > > ext4_split_extent > path = *ppath = 2000 > ext4_find_extent > if (depth > path[0].p_maxdepth) > kfree(path = 2000); > *orig_path = path = NULL; > path = kcalloc() = 3000 > ext4_split_extent_at(*ppath = NULL) > path = *ppath; > ex = path[depth].p_ext; > // NULL pointer dereference! > > ================================================================== > BUG: kernel NULL pointer dereference, address: 0000000000000010 > CPU: 6 UID: 0 PID: 576 Comm: fsstress Not tainted 6.11.0-rc2-dirty #847 > RIP: 0010:ext4_split_extent_at+0x6d/0x560 > Call Trace: > <TASK> > ext4_split_extent.isra.0+0xcb/0x1b0 > ext4_ext_convert_to_initialized+0x168/0x6c0 > ext4_ext_handle_unwritten_extents+0x325/0x4d0 > ext4_ext_map_blocks+0x520/0xdb0 > ext4_map_blocks+0x2b0/0x690 > ext4_iomap_begin+0x20e/0x2c0 > [...] > ================================================================== > > Therefore, *orig_path is updated when the extent lookup succeeds, so that > the caller can safely use path or *ppath. > > Fixes: 10809df84a4d ("ext4: teach ext4_ext_find_extent() to realloc path if necessary") > Cc: stable@xxxxxxxxxx > Signed-off-by: Baokun Li <libaokun1@xxxxxxxxxx> Looks good. Feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > fs/ext4/extents.c | 3 ++- > fs/ext4/move_extent.c | 1 - > 2 files changed, 2 insertions(+), 2 deletions(-) > > diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c > index 0224cf0ef19e..5879aef159d8 100644 > --- a/fs/ext4/extents.c > +++ b/fs/ext4/extents.c > @@ -957,6 +957,8 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block, > > ext4_ext_show_path(inode, path); > > + if (orig_path) > + *orig_path = path; > return path; > > err: > @@ -3268,7 +3270,6 @@ static int ext4_split_extent_at(handle_t *handle, > } > depth = ext_depth(inode); > ex = path[depth].p_ext; > - *ppath = path; > > if (EXT4_EXT_MAY_ZEROOUT & split_flag) { > if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { > diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c > index 204f53b23622..c95e3e526390 100644 > --- a/fs/ext4/move_extent.c > +++ b/fs/ext4/move_extent.c > @@ -36,7 +36,6 @@ get_ext_path(struct inode *inode, ext4_lblk_t lblock, > *ppath = NULL; > return -ENODATA; > } > - *ppath = path; > return 0; > } > > -- > 2.39.2 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR