aboutsummaryrefslogtreecommitdiff
path: root/sys/net/if.c
diff options
context:
space:
mode:
authorMatt Macy <mmacy@FreeBSD.org>2018-08-15 20:23:08 +0000
committerMatt Macy <mmacy@FreeBSD.org>2018-08-15 20:23:08 +0000
commitf9be03860135470f57e32f7fc75c9a3b5afaed80 (patch)
tree45705a0f9043225c5fdc7acbdfecc7e41625b66b /sys/net/if.c
parent8acbb227d9cc40b62c035d0d9d9b54b7872b93d8 (diff)
downloadsrc-f9be03860135470f57e32f7fc75c9a3b5afaed80.tar.gz
src-f9be03860135470f57e32f7fc75c9a3b5afaed80.zip
Fix in6_multi double free
This is actually several different bugs: - The code is not designed to handle inpcb deletion after interface deletion - add reference for inpcb membership - The multicast address has to be removed from interface lists when the refcount goes to zero OR when the interface goes away - decouple list disconnect from refcount (v6 only for now) - ifmultiaddr can exist past being on interface lists - add flag for tracking whether or not it's enqueued - deferring freeing moptions makes the incpb cleanup code simpler but opens the door wider still to races - call inp_gcmoptions synchronously after dropping the the inpcb lock Fundamentally multicast needs a rewrite - but keep applying band-aids for now. Tested by: kp Reported by: novel, kp, lwhsu
Notes
Notes: svn path=/head/; revision=337866
Diffstat (limited to 'sys/net/if.c')
-rw-r--r--sys/net/if.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 6e3d097f7b47..799924d54bb9 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -3545,6 +3545,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
error = ENOMEM;
goto free_llsa_out;
}
+ ll_ifma->ifma_flags |= IFMA_F_ENQUEUED;
CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma,
ifma_link);
} else
@@ -3557,6 +3558,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
* referenced link layer address. Add the primary address to the
* ifnet address list.
*/
+ ifma->ifma_flags |= IFMA_F_ENQUEUED;
CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
if (retifma != NULL)
@@ -3757,9 +3759,10 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
if (--ifma->ifma_refcount > 0)
return 0;
- if (ifp != NULL && detaching == 0)
+ if (ifp != NULL && detaching == 0 && (ifma->ifma_flags & IFMA_F_ENQUEUED)) {
CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
-
+ ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
+ }
/*
* If this ifma is a network-layer ifma, a link-layer ifma may
* have been associated with it. Release it first if so.
@@ -3772,8 +3775,11 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
ll_ifma->ifma_ifp = NULL; /* XXX */
if (--ll_ifma->ifma_refcount == 0) {
if (ifp != NULL) {
- CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr,
- ifma_link);
+ if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
+ CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr,
+ ifma_link);
+ ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
+ }
}
if_freemulti(ll_ifma);
}