DragonFlyBSD Kernel Audit
DF-0580 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netproto/802_11/wlan/ieee80211_input.c b/sys/netproto/802_11/wlan/ieee80211_input.c
--- a/sys/netproto/802_11/wlan/ieee80211_input.c
+++ b/sys/netproto/802_11/wlan/ieee80211_input.c
@@ -247,17 +247,28 @@
 		}
 		mfrag = m;
 	} else {				/* concatenate */
+		uint16_t fraglen;
+		uint16_t seqsave;
+
 		m_adj(m, hdrspace);		/* strip header */
+		/*
+		 * DragonFly's m_cat() may free the source chain's mbufs
+		 * (bcopy + m_free when the fragment data fits the trailing
+		 * space of mfrag's last mbuf).  Capture the values we still
+		 * need from the about-to-be-freed fragment BEFORE m_cat().
+		 */
+		fraglen = m->m_pkthdr.len;
+		seqsave = *(uint16_t *)wh->i_seq;
 #if defined(__DragonFly__)
 		m_cat(mfrag, m);
 		/* NB: m_cat doesn't update the packet header */
-		mfrag->m_pkthdr.len += m->m_pkthdr.len;
+		mfrag->m_pkthdr.len += fraglen;
 #else
 		m_catpkt(mfrag, m);
 #endif
 		/* track last seqnum and fragno */
 		lwh = mtod(mfrag, struct ieee80211_frame *);
-		*(uint16_t *) lwh->i_seq = *(uint16_t *) wh->i_seq;
+		*(uint16_t *) lwh->i_seq = seqsave;
 	}
 	if (more_frag) {			/* more to come, save */
 		ni->ni_rxfragstamp = ticks;