--- a/sys/net/netmap/netmap_generic.c +++ b/sys/net/netmap/netmap_generic.c @@ -98,10 +98,20 @@ * chain into uma_zfree(zone_pack, mf) * (or reinstall the buffer ?) */ -#define SET_MBUF_DESTRUCTOR(m, fn) do { \ - (m)->m_ext.ext_free = (void *)fn; \ - /* (m)->m_ext.ext_type = EXT_EXTREF; */ \ - } while (0) +/* + * DF-3427: never install an mbuf destructor on DragonFly. m_free() + * invokes ext_free(ext_arg) (sys/kern/uipc_mbuf.c:1412,1433) where + * ext_arg is the 16-byte struct mbcluster, not the mbuf, so the + * callback would read m_pkthdr.rcvif out of bounds (offset 40 into a + * 16-byte object) and feed the garbage pointer to + * netmap_generic_irq()->ifp->if_capenable. Worse, a stale ext_free + * survives objcache magazine recycling (the magazine fast path in + * objcache_get() does not re-run the cache ctor), so the booby-trapped + * mbuf detonates in whichever subsystem next recycles it. TX + * completion notification is already provided by + * generic_netmap_tx_clean() polling. + */ +#define SET_MBUF_DESTRUCTOR(m, fn) do { } while (0) #define GET_MBUF_REFCNT(m) ((m)->m_ext.ref_cnt ? *(m)->m_ext.ref_cnt : -1) @@ -319,9 +329,10 @@ * by netmap to transmit a packet. This usually happens when * the NIC notifies the driver that transmission is completed. */ -static void +static void __unused generic_mbuf_destructor(struct mbuf *m) -{ +{ /* kept for documentation; never installed (DF-3427) */ + void *m_ __unused = m; if (netmap_verbose) D("Tx irq (%p) queue %d", m, MBUF_TXQ(m)); netmap_generic_irq(MBUF_IFP(m), MBUF_TXQ(m), NULL);