diff options
author | pluknet <pluknet@FreeBSD.org> | 2011-08-22 23:39:40 +0000 |
---|---|---|
committer | pluknet <pluknet@FreeBSD.org> | 2011-08-22 23:39:40 +0000 |
commit | 081544b729b53a21469898ef85a4f838148d1e71 (patch) | |
tree | d5427dd27753b8ee18fb0c63679269db8626ac90 /sys/netinet6 | |
parent | 4145a19caa34892593779c20f0b391fb661462ed (diff) | |
download | FreeBSD-src-081544b729b53a21469898ef85a4f838148d1e71.zip FreeBSD-src-081544b729b53a21469898ef85a4f838148d1e71.tar.gz |
Fix if_addr_mtx recursion in mld6.
mld_set_version() is called only from mld_v1_input_query() and
mld_v2_input_query() both holding the if_addr_mtx lock, and then calling
into mld_v2_cancel_link_timers() acquires it the second time, which results
in mtx recursion. To avoid that, delay if_addr_mtx acquisition until after
mld_set_version() is called; while here, further reduce locking scope
to protect only the needed pieces: if_multiaddrs, in6m_lookup_locked().
PR: kern/158426
Reported by: Thomas <tps vr-web.de>,
Tom Vijlbrief <tom.vijlbrief xs4all.nl>
Tested by: Tom Vijlbrief
Reviewed by: bz
Approved by: re (kib)
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/mld6.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index 21d9eab..a56f83d 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -680,7 +680,6 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, IN6_MULTI_LOCK(); MLD_LOCK(); - IF_ADDR_LOCK(ifp); /* * Switch to MLDv1 host compatibility mode. @@ -693,6 +692,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, if (timer == 0) timer = 1; + IF_ADDR_LOCK(ifp); if (is_general_query) { /* * For each reporting group joined on this @@ -888,7 +888,6 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, IN6_MULTI_LOCK(); MLD_LOCK(); - IF_ADDR_LOCK(ifp); mli = MLD_IFINFO(ifp); KASSERT(mli != NULL, ("%s: no mld_ifinfo for ifp %p", __func__, ifp)); @@ -936,14 +935,18 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, * Queries for groups we are not a member of on this * link are simply ignored. */ + IF_ADDR_LOCK(ifp); inm = in6m_lookup_locked(ifp, &mld->mld_addr); - if (inm == NULL) + if (inm == NULL) { + IF_ADDR_UNLOCK(ifp); goto out_locked; + } if (nsrc > 0) { if (!ratecheck(&inm->in6m_lastgsrtv, &V_mld_gsrdelay)) { CTR1(KTR_MLD, "%s: GS query throttled.", __func__); + IF_ADDR_UNLOCK(ifp); goto out_locked; } } @@ -961,10 +964,10 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, /* XXX Clear embedded scope ID as userland won't expect it. */ in6_clearscope(&mld->mld_addr); + IF_ADDR_UNLOCK(ifp); } out_locked: - IF_ADDR_UNLOCK(ifp); MLD_UNLOCK(); IN6_MULTI_UNLOCK(); |