⬢ DragonFlyBSD Kernel Audit
DF-4024 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/netif/re/if_revar.h
+++ b/sys/dev/netif/re/if_revar.h
@@ -132,6 +132,8 @@
 	struct callout		re_timer;
 	struct mbuf		*re_head;
 	struct mbuf		*re_tail;
+	int			re_rxchain_len;	/* bytes accumulated in re_head */
+	int			re_rxchain_len;	/* bytes accumulated in re_head */
 	uint32_t		re_caps;	/* see RE_C_ */
 	int			re_rx_desc_cnt;
 	int			re_tx_desc_cnt;
--- a/sys/dev/netif/re/if_re.c
+++ b/sys/dev/netif/re/if_re.c
@@ -291,6 +291,7 @@
 		m_freem(sc->re_head);
 		sc->re_head = sc->re_tail = NULL;
 	}
+	sc->re_rxchain_len = 0;
 }
 
 static int
@@ -1094,6 +1095,7 @@
 
 	sc->re_ldata.re_rx_prodidx = 0;
 	sc->re_head = sc->re_tail = NULL;
+	sc->re_rxchain_len = 0;
 
 	return(0);
 }
@@ -1165,9 +1167,11 @@
 			m->m_len = MCLBYTES;
 			if (sc->re_head == NULL) {
 				sc->re_head = sc->re_tail = m;
+				sc->re_rxchain_len = m->m_len;
 			} else {
 				sc->re_tail->m_next = m;
 				sc->re_tail = m;
+				sc->re_rxchain_len += m->m_len;
 			}
 			continue;
 		} else if (sc->re_flags & RE_F_DROP_RXFRAG) {
@@ -1193,6 +1197,22 @@
 			re_free_rxchain(sc);
 			re_setup_rxdesc(sc, i);
 			continue;
+		}
+
+		/*
+		 * The frame length is device-fed (14-bit GFRAGLEN,
+		 * RE_RXBYTES).  A faulty or malicious NIC can claim
+		 * up to 16383 bytes for a single 2048-byte cluster or
+		 * a total larger than the accumulated fragment chain,
+		 * which would hand out-of-bounds kernel heap to the
+		 * network stack.  Validate it against the geometry.
+		 */
+		if (total_len < ETHER_HDR_LEN + ETHER_CRC_LEN ||
+		    total_len > sc->re_rxbuf_size + sc->re_rxchain_len) {
+			IFNET_STAT_INC(ifp, ierrors, 1);
+			re_free_rxchain(sc);
+			re_setup_rxdesc(sc, i);
+			continue;
 		}
 
 		/*