svn commit: r220487 - stable/8/sys/netinet6

Bjoern A. Zeeb bz at FreeBSD.org
Sat Apr 9 12:11:19 UTC 2011


Author: bz
Date: Sat Apr  9 12:11:19 2011
New Revision: 220487
URL: http://svn.freebsd.org/changeset/base/220487

Log:
  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

Modified:
  stable/8/sys/netinet6/nd6_nbr.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/netinet6/nd6_nbr.c
==============================================================================
--- stable/8/sys/netinet6/nd6_nbr.c	Sat Apr  9 12:04:35 2011	(r220486)
+++ stable/8/sys/netinet6/nd6_nbr.c	Sat Apr  9 12:11:19 2011	(r220487)
@@ -112,7 +112,7 @@ nd6_ns_input(struct mbuf *m, int off, in
 	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, in
 #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, in
 		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, in
 	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);


More information about the svn-src-stable mailing list