Skip to content

Commit 08fc98a

Browse files
Sahitya Tummalatytso
authored andcommitted
ext4: fix use-after-free in dx_release()
The buffer_head (frames[0].bh) and it's corresping page can be potentially free'd once brelse() is done inside the for loop but before the for loop exits in dx_release(). It can be free'd in another context, when the page cache is flushed via drop_caches_sysctl_handler(). This results into below data abort when accessing info->indirect_levels in dx_release(). Unable to handle kernel paging request at virtual address ffffffc17ac3e01e Call trace: dx_release+0x70/0x90 ext4_htree_fill_tree+0x2d4/0x300 ext4_readdir+0x244/0x6f8 iterate_dir+0xbc/0x160 SyS_getdents64+0x94/0x174 Signed-off-by: Sahitya Tummala <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]> Reviewed-by: Andreas Dilger <[email protected]> Cc: [email protected]
1 parent 57a0da2 commit 08fc98a

File tree

1 file changed

+4
-1
lines changed

1 file changed

+4
-1
lines changed

fs/ext4/namei.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,12 +872,15 @@ static void dx_release(struct dx_frame *frames)
872872
{
873873
struct dx_root_info *info;
874874
int i;
875+
unsigned int indirect_levels;
875876

876877
if (frames[0].bh == NULL)
877878
return;
878879

879880
info = &((struct dx_root *)frames[0].bh->b_data)->info;
880-
for (i = 0; i <= info->indirect_levels; i++) {
881+
/* save local copy, "info" may be freed after brelse() */
882+
indirect_levels = info->indirect_levels;
883+
for (i = 0; i <= indirect_levels; i++) {
881884
if (frames[i].bh == NULL)
882885
break;
883886
brelse(frames[i].bh);

0 commit comments

Comments
 (0)