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 <david.chen@osnexus.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
parent
ec9b8fae06
commit
d5b0e7fcf1
|
@ -1379,9 +1379,9 @@ get_zfs_sb(const char *dsname, zfs_sb_t **zsbp)
|
||||||
|
|
||||||
mutex_enter(&os->os_user_ptr_lock);
|
mutex_enter(&os->os_user_ptr_lock);
|
||||||
*zsbp = dmu_objset_get_user(os);
|
*zsbp = dmu_objset_get_user(os);
|
||||||
if (*zsbp && (*zsbp)->z_sb) {
|
/* bump s_active only when non-zero to prevent umount race */
|
||||||
atomic_inc(&((*zsbp)->z_sb->s_active));
|
if (*zsbp == NULL || (*zsbp)->z_sb == NULL ||
|
||||||
} else {
|
!atomic_inc_not_zero(&((*zsbp)->z_sb->s_active))) {
|
||||||
error = SET_ERROR(ESRCH);
|
error = SET_ERROR(ESRCH);
|
||||||
}
|
}
|
||||||
mutex_exit(&os->os_user_ptr_lock);
|
mutex_exit(&os->os_user_ptr_lock);
|
||||||
|
|
Loading…
Reference in New Issue