summaryrefslogtreecommitdiff
path: root/sys/netinet6/nd6_nbr.c
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2011-04-09 12:11:19 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2011-04-09 12:11:19 +0000
commit213e5087e01cf6452ee170472f918e908f6404bf (patch)
tree5424d9f3faece34a85b2c333ffd299b7ca88d7ad /sys/netinet6/nd6_nbr.c
parent6293191b37b56239c3420cc3ee1058e1227e835f (diff)
MFC r219562:
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. Submitted by: chenyl (netstar2008 126.com) (initial version) PR: kern/151908
Notes
svn path=/stable/8/; revision=220487
Diffstat (limited to 'sys/netinet6/nd6_nbr.c')
-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 6b27997856c5..b658d35b7d66 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -112,7 +112,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
@@ -247,18 +247,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) {
@@ -332,7 +339,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;
}
@@ -342,7 +349,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);