summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2011-03-12 09:41:25 +0000
committerbz <bz@FreeBSD.org>2011-03-12 09:41:25 +0000
commitd94569d0eda2904ae51ce50a17605f48f94fff76 (patch)
treebe892239ac63ab1a676bad629496bc5f01134975 /sys/netinet6
parent8b9accae99ebde19a9f203d97a1f1fc163d951e7 (diff)
downloadFreeBSD-src-d94569d0eda2904ae51ce50a17605f48f94fff76.zip
FreeBSD-src-d94569d0eda2904ae51ce50a17605f48f94fff76.tar.gz
Make sure the locally cached value of rt->rt_gateway stays stable,
even after dropping the reference and unlocking. Previously we have dereferenced a NULL pointer (after r121765). Simply unlocking after the block does not work either because of lock ordering (see r121765) and in addition we would still hold a pointer to something that might be gone by the time we access it. Thus take a copy of the value rather than just caching the pointer. PR: kern/151908 Submitted by: chenyl (netstar2008 126.com) (initial version) MFC after: 2 weeks
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/nd6_nbr.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index a100eb6..720ae1f 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -113,7 +113,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
int anycast = 0, proxy = 0, tentative = 0;
int tlladdr;
union nd_opts ndopts;
- struct sockaddr_dl *proxydl = NULL;
+ struct sockaddr_dl proxydl;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
#ifndef PULLDOWN_TEST
@@ -248,18 +248,25 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
#endif
need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
rt->rt_gateway->sa_family == AF_LINK);
- if (rt)
+ if (rt != NULL) {
+ /*
+ * Make a copy while we can be sure that rt_gateway
+ * is still stable before unlocking to avoid lock
+ * order problems. proxydl will only be used if
+ * proxy will be set in the next block.
+ */
+ if (need_proxy)
+ proxydl = *SDL(rt->rt_gateway);
RTFREE_LOCKED(rt);
+ }
if (need_proxy) {
/*
* proxy NDP for single entry
*/
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
- if (ifa) {
+ if (ifa)
proxy = 1;
- proxydl = SDL(rt->rt_gateway);
- }
}
}
if (ifa == NULL) {
@@ -333,7 +340,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
nd6_na_output(ifp, &in6_all, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
(V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
- tlladdr, (struct sockaddr *)proxydl);
+ tlladdr, (struct sockaddr *)&proxydl);
goto freeit;
}
@@ -343,7 +350,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
nd6_na_output(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
(V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
- tlladdr, (struct sockaddr *)proxydl);
+ tlladdr, (struct sockaddr *)&proxydl);
freeit:
if (ifa != NULL)
ifa_free(ifa);
OpenPOWER on IntegriCloud