aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2021-02-08 09:04:27 +0000
committerKristof Provost <kp@FreeBSD.org>2021-02-17 13:13:04 +0000
commit9cc7bd9a6ab1e2bfc12dabf4d9ef4ad463a05616 (patch)
tree9129057b9977f92452702832eeb4c197bed82dbb
parentf8d1f2da0922fdff846b13baa7315652b43aa95c (diff)
Widen ifnet_detach_sxlock coverage
Widen the ifnet_detach_sxlock to cover the entire vnet sysuninit code. This ensures that we can't end up having the vnet_sysuninit free the UDP pcb while the detach code is running and trying to purge the UDP pcb. MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D28530 (cherry picked from commit 6d2a10d96fb5d4ee42fd67b0b07a6d098db5d55a)
-rw-r--r--sys/net/if.c13
-rw-r--r--sys/net/if.h3
-rw-r--r--sys/net/vnet.c2
3 files changed, 11 insertions, 7 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 56b12f594814..2ae8121043b0 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -316,7 +316,8 @@ struct sx ifnet_sxlock;
SX_SYSINIT_FLAGS(ifnet_sx, &ifnet_sxlock, "ifnet_sx", SX_RECURSE);
struct sx ifnet_detach_sxlock;
-SX_SYSINIT(ifnet_detach, &ifnet_detach_sxlock, "ifnet_detach_sx");
+SX_SYSINIT_FLAGS(ifnet_detach, &ifnet_detach_sxlock, "ifnet_detach_sx",
+ SX_RECURSE);
/*
* The allocation of network interfaces is a rather non-atomic affair; we
@@ -552,9 +553,7 @@ vnet_if_return(const void *unused __unused)
IFNET_WUNLOCK();
for (int j = 0; j < i; j++) {
- sx_xlock(&ifnet_detach_sxlock);
if_vmove(pending[j], pending[j]->if_home_vnet);
- sx_xunlock(&ifnet_detach_sxlock);
}
free(pending, M_IFNET);
@@ -1108,9 +1107,9 @@ if_detach(struct ifnet *ifp)
CURVNET_SET_QUIET(ifp->if_vnet);
found = if_unlink_ifnet(ifp, false);
if (found) {
- sx_slock(&ifnet_detach_sxlock);
+ sx_xlock(&ifnet_detach_sxlock);
if_detach_internal(ifp, 0, NULL);
- sx_sunlock(&ifnet_detach_sxlock);
+ sx_xunlock(&ifnet_detach_sxlock);
}
CURVNET_RESTORE();
}
@@ -3147,9 +3146,9 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
error = priv_check(td, PRIV_NET_IFDESTROY);
if (error == 0) {
- sx_slock(&ifnet_detach_sxlock);
+ sx_xlock(&ifnet_detach_sxlock);
error = if_clone_destroy(ifr->ifr_name);
- sx_sunlock(&ifnet_detach_sxlock);
+ sx_xunlock(&ifnet_detach_sxlock);
}
goto out_noref;
diff --git a/sys/net/if.h b/sys/net/if.h
index 3767033d8265..44a920d844e2 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -600,6 +600,9 @@ struct ifdownreason {
MALLOC_DECLARE(M_IFADDR);
MALLOC_DECLARE(M_IFMADDR);
#endif
+
+extern struct sx ifnet_detach_sxlock;
+
#endif
#ifndef _KERNEL
diff --git a/sys/net/vnet.c b/sys/net/vnet.c
index 9a4321a8409b..3fd423d22d1d 100644
--- a/sys/net/vnet.c
+++ b/sys/net/vnet.c
@@ -281,7 +281,9 @@ vnet_destroy(struct vnet *vnet)
VNET_LIST_WUNLOCK();
CURVNET_SET_QUIET(vnet);
+ sx_xlock(&ifnet_detach_sxlock);
vnet_sysuninit();
+ sx_xunlock(&ifnet_detach_sxlock);
CURVNET_RESTORE();
/*