On 2019/8/14 19:14, Jan Kara Wrote: > On Tue 13-08-19 21:05:47, zhangyi (F) wrote: >> Remount process will release system zone which was allocated before if >> "noblock_validity" is specified. If we mount an ext4 file system to two >> mountpoints with default mount options, and then remount one of them >> with "noblock_validity", it may trigger a use after free problem when >> someone accessing the other one. >> >> # mount /dev/sda foo >> # mount /dev/sda bar >> >> User access mountpoint "foo" | Remount mountpoint "bar" >> | >> ext4_map_blocks() | ext4_remount() >> check_block_validity() | ext4_setup_system_zone() >> ext4_data_block_valid() | ext4_release_system_zone() >> | free system_blks rb nodes >> access system_blks rb nodes | >> trigger use after free | >> >> This problem can also be reproduced by one mountpint, At the same time, >> add_system_zone() can get called during remount as well so there can be >> racing ext4_data_block_valid() reading the rbtree at the same time. >> >> This patch add RCU to protect system zone from releasing or building >> when doing a remount which inverse current "noblock_validity" mount >> option. It assign the rbtree after the whole tree was complete and >> do actual freeing after rcu grace period, avoid any intermediate state. >> >> Signed-off-by: zhangyi (F) <yi.zhang@xxxxxxxxxx> >> --- >> Changes since v2: >> - Remove seqlock, and assign the whole rbtree when finished assembling. >> - Fix the sparse warning. > > Thanks for the patch! It looks great to me. Just one nit below and with > that applied feel free to add: > > Reviewed-by: Jan Kara <jack@xxxxxxx> > >> int ext4_setup_system_zone(struct super_block *sb) > ... >> /* Called when the filesystem is unmounted */ >> void ext4_release_system_zone(struct super_block *sb) > > Can you perhaps add a comment before ext4_setup_system_zone() and > ext4_release_system_zone() explaining that these two functions are called > under sb->s_umount semaphore protection which also serializes updates of > sb->system_blks pointer? Thanks! > Thanks for your suggestions. Yes, I will add these two comments. BTW, I realize that one thing is not correct in this patch, ext4_data_block_valid() should do the below check as before even system_blks pointer is NULL. > if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || > (start_blk + count < start_blk) || > (start_blk + count > ext4_blocks_count(sbi->s_es))) { > sbi->s_es->s_last_error_block = cpu_to_le64(start_blk); > return 0; > } I will fix this by move "system_blks == NULL" checking into ext4_data_block_valid_rcu() in next iteration at the same time. Thanks, Yi.