Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 Mar 2011 09:41:26 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r219562 - head/sys/netinet6
Message-ID:  <201103120941.p2C9fQdd011445@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Sat Mar 12 09:41:25 2011
New Revision: 219562
URL: http://svn.freebsd.org/changeset/base/219562

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

Modified:
  head/sys/netinet6/nd6_nbr.c

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c	Sat Mar 12 09:09:25 2011	(r219561)
+++ head/sys/netinet6/nd6_nbr.c	Sat Mar 12 09:41:25 2011	(r219562)
@@ -113,7 +113,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
@@ -248,18 +248,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) {
@@ -333,7 +340,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;
 	}
 
@@ -343,7 +350,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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103120941.p2C9fQdd011445>