DragonFlyBSD Kernel Audit
DF-0997 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/u4b/wlan/if_rum.c b/sys/bus/u4b/wlan/if_rum.c
@@ -1218,7 +1218,31 @@
 		}
 
 		/* finalize mbuf */
-		m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff;
+		{
+			unsigned int pktlen = (flags >> 16) & 0xfff;
+
+			/*
+			 * The RX descriptor length field is device-controlled.
+			 * A malicious or faulty USB device can advertise a length
+			 * larger than what we actually received (and larger than
+			 * the mbuf cluster), which would cause subsequent
+			 * net80211/BPF readers to walk off the cluster into
+			 * kernel heap.  Clamp to the host-controller-bounded
+			 * actlen-derived `len` and drop if bogus.  See DF-0997.
+			 */
+			if (pktlen > (unsigned int)len || pktlen > MCLBYTES) {
+				DPRINTF("%s: bogus rx length %u (> %d)\n",
+				    device_get_nameunit(sc->sc_dev), pktlen, len);
+#if defined(__DragonFly__)
+				++ic->ic_ierrors;
+#else
+				counter_u64_add(ic->ic_ierrors, 1);
+#endif
+				m_freem(m);
+				goto tr_setup;
+			}
+			m->m_pkthdr.len = m->m_len = pktlen;
+		}
 
 		if (ieee80211_radiotap_active(ic)) {
 			struct rum_rx_radiotap_header *tap = &sc->sc_rxtap;