pppx_if_start() checks `IFF_RUNNING' bit to be sure `pxi' is consistent but this bit is not cleared on `pxi' destroy. pppx_if_output() checks `IFF_UP' bit for the same reason but this bit is always set and this check is useless. pppac_output() checks `IFF_RUNNING' bit but pppac_start() doesn't.
Diff below adds `IFF_RUNNING' clearing to pppx_if_destroy() before `pxi' destruction to be sure this `pxi' can't be accessed from `ifnet' in potencial context switch caused by if_detach(). In pppx_if_output() `IFF_RUNNING' checked instead of `IFF_UP' for consistency with other code. Also `IFF_RUNNING' checked in pppac_start(). Index: sys/net/if_pppx.c =================================================================== RCS file: /cvs/src/sys/net/if_pppx.c,v retrieving revision 1.89 diff -u -p -r1.89 if_pppx.c --- sys/net/if_pppx.c 22 Jun 2020 10:01:03 -0000 1.89 +++ sys/net/if_pppx.c 22 Jun 2020 11:59:28 -0000 @@ -854,9 +854,10 @@ pppx_if_destroy(struct pppx_dev *pxd, st struct pipex_session *session; NET_ASSERT_LOCKED(); - pxi->pxi_ready = 0; session = pxi->pxi_session; ifp = &pxi->pxi_if; + pxi->pxi_ready = 0; + CLR(ifp->if_flags, IFF_RUNNING); pipex_unlink_session(session); @@ -910,7 +911,7 @@ pppx_if_output(struct ifnet *ifp, struct NET_ASSERT_LOCKED(); - if (!ISSET(ifp->if_flags, IFF_UP)) { + if (!ISSET(ifp->if_flags, IFF_RUNNING)) { m_freem(m); error = ENETDOWN; goto out; @@ -1465,6 +1466,9 @@ pppac_start(struct ifnet *ifp) { struct pppac_softc *sc = ifp->if_softc; struct mbuf *m; + + if (!ISSET(ifp->if_flags, IFF_RUNNING)) + return; while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) { #if NBPFILTER > 0