svn commit: r291301 - head/sys/netinet

Fabien Thomas fabient at FreeBSD.org
Wed Nov 25 14:45:45 UTC 2015


Author: fabient
Date: Wed Nov 25 14:45:43 2015
New Revision: 291301
URL: https://svnweb.freebsd.org/changeset/base/291301

Log:
  The r241129 description was wrong that the scenario is possible
  only for read locks on pcbs. The same race can happen with write
  lock semantics as well.
  
  The race scenario:
  
  - Two threads (1 and 2) locate pcb with writer semantics (INPLOOKUP_WLOCKPCB)
   and do in_pcbref() on it.
  - 1 and 2 both drop the inp hash lock.
  - Another thread (3) grabs the inp hash lock. Then it runs in_pcbfree(),
   which wlocks the pcb. They must happen faster than 1 or 2 come INP_WLOCK()!
  - 1 and 2 congest in INP_WLOCK().
  - 3 does in_pcbremlists(), drops hash lock, and runs in_pcbrele_wlocked(),
   which doesn't free the pcb due to two references on it.
   Then it unlocks the pcb.
  - 1 (or 2) gets wlock on the pcb, runs in_pcbrele_wlocked(), which doesn't
   report inp as freed, due to 2 (or 1) still helding extra reference on it.
   The thread tries to do smth with a disconnected pcb and crashes.
  
  Submitted by:	emeric.poupon at stormshield.eu
  Reviewed by:	gleb@
  MFC after:	1 week
  Sponsored by: Stormshield
  Tested by: Cassiano Peixoto, Stormshield

Modified:
  head/sys/netinet/in_pcb.c

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c	Wed Nov 25 13:26:42 2015	(r291300)
+++ head/sys/netinet/in_pcb.c	Wed Nov 25 14:45:43 2015	(r291301)
@@ -1220,8 +1220,17 @@ in_pcbrele_wlocked(struct inpcb *inp)
 
 	INP_WLOCK_ASSERT(inp);
 
-	if (refcount_release(&inp->inp_refcount) == 0)
+	if (refcount_release(&inp->inp_refcount) == 0) {
+		/*
+		 * If the inpcb has been freed, let the caller know, even if
+		 * this isn't the last reference.
+		 */
+		if (inp->inp_flags2 & INP_FREED) {
+			INP_WUNLOCK(inp);
+			return (1);
+		}
 		return (0);
+	}
 
 	KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__));
 


More information about the svn-src-all mailing list