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
This commit is contained in:
Bjoern A. Zeeb 2011-03-12 09:41:25 +00:00
parent 308bce2a0e
commit 8b529ca61e

View File

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