aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2016-07-08 16:59:54 -0700
committerBrian Behlendorf <[email protected]>2016-07-12 13:34:14 -0700
commit061460dfe222e01f258db7f6bad689c1ebd2634e (patch)
treed83a88afb23bbb9b4e667fdce511629898ed5843 /module
parent590c9a09946939a389e1f01dadd27efb4b2fe8fd (diff)
Fix get_zfs_sb race with concurrent umount
Certain ioctl operations will call get_zfs_sb, which will holds an active count on sb without checking whether it's active or not. This will result in use-after-free. We fix this by using atomic_inc_not_zero to make sure we got an active sb. P1 P2 --- --- deactivate_locked_super(): s_active = 0 zfs_sb_hold() ->get_zfs_sb(): s_active = 1 ->zpl_kill_sb() -->zpl_put_super() --->zfs_umount() ---->zfs_sb_free(zsb) zfs_sb_rele(zsb) Signed-off-by: Chunwei Chen <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module')
-rw-r--r--module/zfs/zfs_ioctl.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index 09f83a5cf..f607225d1 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -1393,9 +1393,9 @@ get_zfs_sb(const char *dsname, zfs_sb_t **zsbp)
mutex_enter(&os->os_user_ptr_lock);
*zsbp = dmu_objset_get_user(os);
- if (*zsbp && (*zsbp)->z_sb) {
- atomic_inc(&((*zsbp)->z_sb->s_active));
- } else {
+ /* bump s_active only when non-zero to prevent umount race */
+ if (*zsbp == NULL || (*zsbp)->z_sb == NULL ||
+ !atomic_inc_not_zero(&((*zsbp)->z_sb->s_active))) {
error = SET_ERROR(ESRCH);
}
mutex_exit(&os->os_user_ptr_lock);