summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasomers <asomers@FreeBSD.org>2016-04-12 19:11:14 +0000
committerasomers <asomers@FreeBSD.org>2016-04-12 19:11:14 +0000
commit2a0941fb20351d00765ce970ea44efcc0f389e3b (patch)
tree7e214f1efce7e020f0af85f84af5015188069167
parent59b487552b970f0667b23ad1197bc0a224a5048c (diff)
downloadFreeBSD-src-2a0941fb20351d00765ce970ea44efcc0f389e3b.zip
FreeBSD-src-2a0941fb20351d00765ce970ea44efcc0f389e3b.tar.gz
Fix rare double free in vdev_geom_attrchanged
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c Don't drop the g_topology_lock before freeing old_physpath. That opens up a race where one thread can call vdev_geom_attrchanged, set old_physpath, drop the g_topology_lock, then block trying to acquire the SCL_STATE lock. Then another thread can come into vdev_geom_attrchanged, set old_physpath to the same value, and proceed to free it. When the first thread resumes, it will free the same location. It turns out that the SCL_STATE lock isn't needed. It was originally added by gibbs to protect vd->vdev_physpath while updating the same. However, the update process subsequently was switched to an atomic operation (a pointer swap). Now, there is no need for the SCL_STATE lock, and hence no need to drop the g_topology_lock. Reviewed by: delphij MFC after: 4 weeks Sponsored by: Spectra Logic Corp Differential Revision: https://reviews.freebsd.org/D5413
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c19
1 files changed, 3 insertions, 16 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
index f459655..1777fba 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
@@ -115,27 +115,14 @@ vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
if (error == 0) {
char *old_physpath;
+ /* g_topology lock ensures that vdev has not been closed */
+ g_topology_assert();
old_physpath = vd->vdev_physpath;
vd->vdev_physpath = spa_strdup(physpath);
spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
- if (old_physpath != NULL) {
- int held_lock;
-
- held_lock = spa_config_held(spa, SCL_STATE, RW_WRITER);
- if (held_lock == 0) {
- g_topology_unlock();
- spa_config_enter(spa, SCL_STATE, FTAG,
- RW_WRITER);
- }
-
+ if (old_physpath != NULL)
spa_strfree(old_physpath);
-
- if (held_lock == 0) {
- spa_config_exit(spa, SCL_STATE, FTAG);
- g_topology_lock();
- }
- }
}
g_free(physpath);
}
OpenPOWER on IntegriCloud