1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-06 13:09:50 +00:00

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)
This commit is contained in:
Sergey Kandaurov 2011-08-22 23:39:40 +00:00
parent 11867070c6
commit 0ad2addc9d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=225096

View File

@ -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();