Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Aug 2017 19:40:07 +0000 (UTC)
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r322590 - head/sys/net
Message-ID:  <201708161940.v7GJe7OI099848@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kp
Date: Wed Aug 16 19:40:07 2017
New Revision: 322590
URL: https://svnweb.freebsd.org/changeset/base/322590

Log:
  bpf: Fix incorrect cleanup
  
  Cleaning up a bpf_if is a two stage process. We first move it to the
  bpf_freelist (in bpfdetach()) and only later do we actually free it (in
  bpf_ifdetach()).
  
  We cannot set the ifp->if_bpf to NULL from bpf_ifdetach() because it's
  possible that the ifnet has already gone away, or that it has been assigned
  a new bpf_if.
  This can lead to a struct ifnet which is up, but has if_bpf set to NULL,
  which will panic when we try to send the next packet.
  
  Keep track of the pointer to the bpf_if (because it's not always
  ifp->if_bpf), and NULL it immediately in bpfdetach().
  
  PR:		213896
  MFC after:	2 weeks
  Differential Revision:	https://reviews.freebsd.org/D11782

Modified:
  head/sys/net/bpf.c

Modified: head/sys/net/bpf.c
==============================================================================
--- head/sys/net/bpf.c	Wed Aug 16 18:55:39 2017	(r322589)
+++ head/sys/net/bpf.c	Wed Aug 16 19:40:07 2017	(r322590)
@@ -106,6 +106,7 @@ struct bpf_if {
 	struct rwlock	bif_lock;	/* interface lock */
 	LIST_HEAD(, bpf_d) bif_wlist;	/* writer-only list */
 	int		bif_flags;	/* Interface flags */
+	struct bpf_if	**bif_bpf;	/* Pointer to pointer to us */
 };
 
 CTASSERT(offsetof(struct bpf_if, bif_ext) == 0);
@@ -2563,6 +2564,7 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen,
 	bp->bif_dlt = dlt;
 	rw_init(&bp->bif_lock, "bpf interface lock");
 	KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized"));
+	bp->bif_bpf = driverp;
 	*driverp = bp;
 
 	BPF_LOCK();
@@ -2633,6 +2635,7 @@ bpfdetach(struct ifnet *ifp)
 		 */
 		BPFIF_WLOCK(bp);
 		bp->bif_flags |= BPFIF_FLAG_DYING;
+		*bp->bif_bpf = NULL;
 		BPFIF_WUNLOCK(bp);
 
 		CTR4(KTR_NET, "%s: sheduling free for encap %d (%p) for if %p",
@@ -2702,13 +2705,6 @@ bpf_ifdetach(void *arg __unused, struct ifnet *ifp)
 		nmatched++;
 	}
 	BPF_UNLOCK();
-
-	/*
-	 * Note that we cannot zero other pointers to
-	 * custom DLTs possibly used by given interface.
-	 */
-	if (nmatched != 0)
-		ifp->if_bpf = NULL;
 }
 
 /*



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