Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 2 Dec 2015 17:26:37 +0000 (UTC)
From:      Fabien Thomas <fabient@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r291652 - stable/10/sys/netinet
Message-ID:  <201512021726.tB2HQb5p056013@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: fabient
Date: Wed Dec  2 17:26:37 2015
New Revision: 291652
URL: https://svnweb.freebsd.org/changeset/base/291652

Log:
  MFC r291301:
  
  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@stormshield.eu
   Reviewed by:	glebius@
   Sponsored by: Stormshield
   Tested by: Cassiano Peixoto, Stormshield

Modified:
  stable/10/sys/netinet/in_pcb.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/netinet/in_pcb.c
==============================================================================
--- stable/10/sys/netinet/in_pcb.c	Wed Dec  2 16:29:36 2015	(r291651)
+++ stable/10/sys/netinet/in_pcb.c	Wed Dec  2 17:26:37 2015	(r291652)
@@ -1148,8 +1148,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__));
 



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