⬢ DragonFlyBSD Kernel Audit
DF-3427 / fix.diff
← back to finding ↓ download raw
--- 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);