diff options
author | zhangyi (F) <yi.zhang@huawei.com> | 2019-08-28 11:13:24 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2019-08-28 11:13:24 -0400 |
commit | 7727ae52975d4f4ef7ff69ed8e6e25f6a4168158 (patch) | |
tree | d002cc6f188ab3980339fb38d0ae6b684d43ece7 /fs/ext4/ext4.h | |
parent | 4c273352bb4583750bf511fe24fe410610414496 (diff) |
ext4: fix potential use after free after remounting with noblock_validity
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.
Reported-by: syzbot+1e470567330b7ad711d5@syzkaller.appspotmail.com
Signed-off-by: zhangyi (F) <yi.zhang@huawei.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext4/ext4.h')
-rw-r--r-- | fs/ext4/ext4.h | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0664c43cc9dc..c35bb8d734df 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -185,6 +185,14 @@ struct ext4_map_blocks { | |||
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* | 187 | /* |
188 | * Block validity checking, system zone rbtree. | ||
189 | */ | ||
190 | struct ext4_system_blocks { | ||
191 | struct rb_root root; | ||
192 | struct rcu_head rcu; | ||
193 | }; | ||
194 | |||
195 | /* | ||
188 | * Flags for ext4_io_end->flags | 196 | * Flags for ext4_io_end->flags |
189 | */ | 197 | */ |
190 | #define EXT4_IO_END_UNWRITTEN 0x0001 | 198 | #define EXT4_IO_END_UNWRITTEN 0x0001 |
@@ -1431,7 +1439,7 @@ struct ext4_sb_info { | |||
1431 | int s_jquota_fmt; /* Format of quota to use */ | 1439 | int s_jquota_fmt; /* Format of quota to use */ |
1432 | #endif | 1440 | #endif |
1433 | unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ | 1441 | unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ |
1434 | struct rb_root system_blks; | 1442 | struct ext4_system_blocks __rcu *system_blks; |
1435 | 1443 | ||
1436 | #ifdef EXTENTS_STATS | 1444 | #ifdef EXTENTS_STATS |
1437 | /* ext4 extents stats */ | 1445 | /* ext4 extents stats */ |