⬢ DragonFlyBSD Kernel Audit
DF-3759 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/netif/alc/if_alc.c
+++ b/sys/dev/netif/alc/if_alc.c
@@ -3305,6 +3305,21 @@
 	nsegs = RRD_RD_CNT(rdinfo);
 
 	sc->alc_cdata.alc_rxlen = RRD_BYTES(status);
+	/*
+	 * Do not trust the controller-written frame length: the RRS
+	 * length field is 14 bits wide (up to 16383) while the frame
+	 * was DMA'd into at most nsegs buffers of alc_buf_size bytes
+	 * each.  A faulty or malicious controller must not be able to
+	 * hand the network stack an mbuf chain whose m_len /
+	 * m_pkthdr.len describes more data than the clusters actually
+	 * hold (heap OOB read of up to ~14KB past a 2KB cluster), nor
+	 * lengths below ETHER_CRC_LEN (signed underflow in the CRC
+	 * strip below).  Drop the frame; the buffers are reused in
+	 * place, same as the CRC/runt error path below.
+	 */
+	if (sc->alc_cdata.alc_rxlen > nsegs * sc->alc_buf_size ||
+	    sc->alc_cdata.alc_rxlen < ETHER_CRC_LEN)
+		return;
 	if ((status & (RRD_ERR_SUM | RRD_ERR_LENGTH)) != 0) {
 		/*
 		 * We want to pass the following frames to upper