svn commit: r249478 - in stable/8/sys: netinet netinet6

Robert Watson rwatson at FreeBSD.org
Sun Apr 14 16:25:38 UTC 2013


Author: rwatson
Date: Sun Apr 14 16:25:37 2013
New Revision: 249478
URL: http://svnweb.freebsd.org/changeset/base/249478

Log:
  FreeBSD 8.0 introduced inpcb reference counting, and FreeBSD 8.1 began using
  that reference count to protect inpcb stability in udp_pcblist() and other
  monitoring functions, preventing the inpcb from being garbage collected
  across potentially sleeping copyout() operations despite the inpcb zone
  becoming shrinkable.
  
  However, this introduced a race condition in which inp->inp_socket() might
  become NULL as a result of the socket being freed, but before the inpcb we
  removed from the global list of connections, allowing it to be exposed to a
  third thread invoking udp_input() or udp6_input() which would try to
  indirect through inp_socket without testing it for NULL.  This might occur
  with particular regularity on systems that frequently run netstat, or which
  use SNMP for connection monitoring.
  
  Later FreeBSD releases use a different reference/destruction model, but
  stable/8 remained affected in FreeBSD 8.2 and 8.3; the problem could be
  spotted on very high-load UDP services, such as top-level name servers.
  
  An Errata Note for 8.x branches under continuing support might be
  appropriate.  Regardless, this fix should be merged to releng/8.4 prior to
  8.4-RELEASE.
  
  PR:		172963
  Submitted by:	Vincent Miller <vmiller at verisign.com>
  Submitted by:	Julien Charbon <jcharbon at verisign.com>
  Submitted by:	Marc De La Gueronniere <mdelagueronniere at verisign.com>

Modified:
  stable/8/sys/netinet/udp_usrreq.c
  stable/8/sys/netinet6/udp6_usrreq.c

Modified: stable/8/sys/netinet/udp_usrreq.c
==============================================================================
--- stable/8/sys/netinet/udp_usrreq.c	Sun Apr 14 16:20:25 2013	(r249477)
+++ stable/8/sys/netinet/udp_usrreq.c	Sun Apr 14 16:25:37 2013	(r249478)
@@ -495,6 +495,15 @@ udp_input(struct mbuf *m, int off)
 			INP_RLOCK(inp);
 
 			/*
+			 * Detached PCBs can linger in the list if someone
+			 * holds a reference. (e.g. udp_pcblist)
+			 */
+			if (inp->inp_socket == NULL) {
+				INP_RUNLOCK(inp);
+				continue;
+			}
+
+			/*
 			 * Handle socket delivery policy for any-source
 			 * and source-specific multicast. [RFC3678]
 			 */
@@ -620,6 +629,15 @@ udp_input(struct mbuf *m, int off)
 	 */
 	INP_RLOCK(inp);
 	INP_INFO_RUNLOCK(&V_udbinfo);
+
+	/*
+	 * Detached PCBs can linger in the hash table if someone holds a
+	 * reference. (e.g. udp_pcblist)
+	 */
+	if (inp->inp_socket == NULL) {
+		INP_RUNLOCK(inp);
+		goto badunlocked;
+	}
 	if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) {
 		INP_RUNLOCK(inp);
 		goto badunlocked;

Modified: stable/8/sys/netinet6/udp6_usrreq.c
==============================================================================
--- stable/8/sys/netinet6/udp6_usrreq.c	Sun Apr 14 16:20:25 2013	(r249477)
+++ stable/8/sys/netinet6/udp6_usrreq.c	Sun Apr 14 16:25:37 2013	(r249478)
@@ -273,6 +273,13 @@ udp6_input(struct mbuf **mp, int *offp, 
 			}
 
 			/*
+			 * Detached PCBs can linger in the list if someone
+			 * holds a reference. (e.g. udp_pcblist)
+			 */
+			if (inp->inp_socket == NULL)
+				continue;
+
+			/*
 			 * Handle socket delivery policy for any-source
 			 * and source-specific multicast. [RFC3678]
 			 */
@@ -396,6 +403,15 @@ udp6_input(struct mbuf **mp, int *offp, 
 	}
 	INP_RLOCK(inp);
 	INP_INFO_RUNLOCK(&V_udbinfo);
+
+	/*
+	 * Detached PCBs can linger in the hash table if someone holds a
+	 * reference. (e.g. udp_pcblist)
+	 */
+	if (inp->inp_socket == NULL) {
+		INP_RUNLOCK(inp);
+		goto badunlocked;
+	}
 	up = intoudpcb(inp);
 	if (up->u_tun_func == NULL) {
 		udp6_append(inp, m, off, &fromsa);


More information about the svn-src-all mailing list