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;
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to