Page MenuHomeFreeBSD

D53438.id165374.diff
No OneTemporary

D53438.id165374.diff

diff --git a/sys/net/if_tuntap.c b/sys/net/if_tuntap.c
--- a/sys/net/if_tuntap.c
+++ b/sys/net/if_tuntap.c
@@ -649,7 +649,7 @@
error = cv_wait_sig(&tp->tun_cv, &tp->tun_mtx);
else
cv_wait(&tp->tun_cv, &tp->tun_mtx);
- if (error != 0) {
+ if (error != 0 && tp->tun_busy != 0) {
tp->tun_flags &= ~TUN_DYING;
TUN_UNLOCK(tp);
return (error);
@@ -661,10 +661,21 @@
mtx_lock(&tunmtx);
TAILQ_REMOVE(&tunhead, tp, tun_list);
- mtx_unlock(&tunmtx);
- /* destroy_dev will take care of any alias. */
- destroy_dev(tp->tun_dev);
+ /*
+ * destroy_dev() will take care of any alias. For transient tunnels,
+ * we're being called from close(2) so we can't destroy it ourselves
+ * without deadlocking, but we already know that we can cleanup
+ * everything else and just continue to prevent it from being reopened.
+ */
+ if ((tp->tun_flags & TUN_TRANSIENT) != 0) {
+ tp->tun_dev->si_drv1 = tp->tun_dev;
+ mtx_unlock(&tunmtx);
+ destroy_dev_sched(tp->tun_dev);
+ } else {
+ mtx_unlock(&tunmtx);
+ destroy_dev(tp->tun_dev);
+ }
seldrain(&tp->tun_rsel);
knlist_clear(&tp->tun_rsel.si_note, 0);
knlist_destroy(&tp->tun_rsel.si_note);
@@ -742,6 +753,7 @@
mtx_unlock(&tunmtx);
for (i = 0; i < nitems(tuntap_drivers); ++i) {
drv = &tuntap_drivers[i];
+ destroy_dev_drain(&drv->cdevsw);
delete_unrhdr(drv->unrhdr);
clone_cleanup(&drv->clones);
}
@@ -1116,17 +1128,45 @@
return (error); /* Shouldn't happen */
}
+ /*
+ * Transient tunnels do deferred destroy of the tun device but want
+ * to immediately cleanup state, so they clobber si_drv1 to avoid a
+ * use-after-free in case someone does happen to open it in the interim.
+ * We avoid using NULL to be able to distinguish from an uninitialized
+ * cdev.
+ *
+ * tun_destroy() takes the tunmtx to do the swap so that we can safely
+ * handle a concurrent tunopen(). If it hasn't been swapped out yet,
+ * then we can safely take its lock and check if it's dying without
+ * risk as long as we're still holding the tunmtx.
+ */
+ mtx_lock(&tunmtx);
+ if (dev->si_drv1 == dev) {
+ mtx_unlock(&tunmtx);
+ CURVNET_RESTORE();
+ return (ENXIO);
+ }
+
tp = dev->si_drv1;
KASSERT(tp != NULL,
("si_drv1 should have been initialized at creation"));
TUN_LOCK(tp);
+ if ((tp->tun_flags & TUN_DYING) != 0) {
+ TUN_UNLOCK(tp);
+ mtx_unlock(&tunmtx);
+ CURVNET_RESTORE();
+ return (EBUSY);
+ }
+
+ mtx_unlock(&tunmtx);
+
if ((tp->tun_flags & TUN_INITED) == 0) {
TUN_UNLOCK(tp);
CURVNET_RESTORE();
return (ENXIO);
}
- if ((tp->tun_flags & (TUN_OPEN | TUN_DYING)) != 0) {
+ if ((tp->tun_flags & TUN_OPEN) != 0) {
TUN_UNLOCK(tp);
CURVNET_RESTORE();
return (EBUSY);

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 24, 3:09 PM (7 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24497867
Default Alt Text
D53438.id165374.diff (2 KB)

Event Timeline