From 36df510d22d86ad68f440c162da8801f7ca54f35 Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Fri, 8 Jul 2016 16:59:54 -0700 Subject: [PATCH] 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 Signed-off-by: Brian Behlendorf --- module/zfs/zfs_ioctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 745f7132bee8..3ebe28d7fcfc 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -1379,9 +1379,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);