On Tue, Jul 04, 2023 at 03:26:30PM +1000, David Gwynne wrote:
> tl;dr: this adds sec(4) p2p ip interfaces. Traffic in and out of these
> interfaces is protected by IPsec security associations (SAs), but
> there's no flows (security policy database (SPD) entries) associated
> with these SAs. The policy for using the sec(4) interfaces and their
> SAs is route-based instead.
>
Hi,
I don't like this sleep with netlock held. sec_send() handler has the
netlock provided sleep point, so concurrent sec_ioctl() could grab
netlock and call sec_down() while sec_send() awaiting netlock release.
So sec_down() will sleep with netlock held awaiting sec_send() to finish
and sec_send() will sleep awaiting netlock acquisition. Smells like
deadlock.
Could you move taskq_del_barrier() and refcnt_finalize() to
sec_clone_destroy() to prevent this?
> +static int
> +sec_down(struct sec_softc *sc)
> +{
> + struct ifnet *ifp = &sc->sc_if;
> + unsigned int idx = stoeplitz_h32(sc->sc_unit) % nitems(sec_map);
> +
> + NET_ASSERT_LOCKED();
> +
> + CLR(ifp->if_flags, IFF_RUNNING);
> +
> + SMR_SLIST_REMOVE_LOCKED(&sec_map[idx], sc, sec_softc, sc_entry);
> +
> + smr_barrier();
> + taskq_del_barrier(systq, &sc->sc_send);
> +
> + refcnt_finalize(&sc->sc_refs, "secdown");
> +
> + return (0);
> +}
> +
> +static void
> +sec_send(void *arg)
> +{
> + struct sec_softc *sc = arg;
> + struct ifnet *ifp = &sc->sc_if;
> + struct ifqueue *ifq = &ifp->if_snd;
> + struct tdb *tdb;
> + struct mbuf *m;
> + int error;
> +
> + if (!ISSET(ifp->if_flags, IFF_RUNNING))
> + return;
> +
> + tdb = sec_tdb_get(sc->sc_unit);
> + if (tdb == NULL)
> + goto purge;
> +
> + NET_LOCK();
> + while ((m = ifq_dequeue(ifq)) != NULL) {
> + CLR(m->m_flags, M_BCAST|M_MCAST);
> +
> +#if NPF > 0
> + pf_pkt_addr_changed(m);
> +#endif
> +
> + error = ipsp_process_packet(m, tdb,
> + m->m_pkthdr.ph_family, /* already tunnelled? */ 0);
> + if (error != 0)
> + counters_inc(ifp->if_counters, ifc_oerrors);
> + }
> + NET_UNLOCK();
> +
> + tdb_unref(tdb);
> + return;
> +
> +purge:
> + counters_add(ifp->if_counters, ifc_oerrors, ifq_purge(ifq));
> +}
> +
Nothing denies sec_start() be MP safe. No reason to wait or stop the
rest of kernel locked code here.
> +static void
> +sec_start(struct ifnet *ifp)
> +{
> + counters_add(ifp->if_counters, ifc_oerrors, ifq_purge(&ifp->if_snd));
> +}