git: 6ca0ca7b4cb5 - main - IPv4 multicast: fix LOR in shutdown path
Date: Mon, 11 Apr 2022 19:52:13 UTC
The branch main has been updated by karels: URL: https://cgit.FreeBSD.org/src/commit/?id=6ca0ca7b4cb527dc17c289f1ae177ec267fd1add commit 6ca0ca7b4cb527dc17c289f1ae177ec267fd1add Author: Mike Karels <karels@FreeBSD.org> AuthorDate: 2022-04-08 12:37:15 +0000 Commit: Mike Karels <karels@FreeBSD.org> CommitDate: 2022-04-11 19:51:16 +0000 IPv4 multicast: fix LOR in shutdown path X_ip_mrouter_done() was calling the interface ioctl routines via if_allmulti() while holding a write lock. However, some interface ioctl routines, including em/iflib and tap, use sxlocks, which are not permitted while holding a non-sleepable lock, and this elicits a warning from WITNESS. Fix the locking issue by recording the affected interface pointers in a malloc'ed array, and call if_allmulti() on each after dropping the rwlock. Reviewed by: bz Differential Revision: https://reviews.freebsd.org/D34845 --- sys/netinet/ip_mroute.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index cc356e3678f3..f77898fb3aa4 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -747,7 +747,8 @@ ip_mrouter_init(struct socket *so, int version) static int X_ip_mrouter_done(void) { - struct ifnet *ifp; + struct ifnet **ifps; + int nifp; u_long i; vifi_t vifi; struct bw_upcall *bu; @@ -774,6 +775,8 @@ X_ip_mrouter_done(void) taskqueue_drain(V_task_queue, &V_task); } + ifps = malloc(MAXVIFS * sizeof(*ifps), M_TEMP, M_WAITOK); + MRW_WLOCK(); taskqueue_cancel(V_task_queue, &V_task, NULL); @@ -785,14 +788,17 @@ X_ip_mrouter_done(void) mtx_destroy(&V_bw_upcalls_ring_mtx); /* - * For each phyint in use, disable promiscuous reception of all IP - * multicasts. + * For each phyint in use, prepare to disable promiscuous reception + * of all IP multicasts. Defer the actual call until the lock is released; + * just record the list of interfaces while locked. Some interfaces use + * sx locks in their ioctl routines, which is not allowed while holding + * a non-sleepable lock. */ - for (vifi = 0; vifi < V_numvifs; vifi++) { + KASSERT(V_numvifs <= MAXVIFS, ("More vifs than possible")); + for (vifi = 0, nifp = 0; vifi < V_numvifs; vifi++) { if (!in_nullhost(V_viftable[vifi].v_lcl_addr) && !(V_viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) { - ifp = V_viftable[vifi].v_ifp; - if_allmulti(ifp, 0); + ifps[nifp++] = V_viftable[vifi].v_ifp; } } bzero((caddr_t)V_viftable, sizeof(*V_viftable) * MAXVIFS); @@ -824,6 +830,14 @@ X_ip_mrouter_done(void) MRW_WUNLOCK(); + /* + * Now drop our claim on promiscuous multicast on the interfaces recorded + * above. This is safe to do now because ALLMULTI is reference counted. + */ + for (vifi = 0; vifi < nifp; vifi++) + if_allmulti(ifps[vifi], 0); + free(ifps, M_TEMP); + CTR1(KTR_IPMF, "%s: done", __func__); return 0;