⬢ DragonFlyBSD Kernel Audit
DF-4270 / fix_validated.diff
← back to finding ↓ download raw
fix.diff — COMBINED validation patch for DF-4267 / DF-4268 / DF-4270
(sys/dev/netif/wb/if_wb.c). Semantically identical to the three seed
fix.diffs (regenerated mechanically so the hunks apply; the seed
diffs' hunk-count headers were off by one and never applied).
Applied only inside the guest's /usr/src for the fix-validation
build — never to the audit tree.

--- if_wb.c.orig	(stock sys/dev/netif/wb/if_wb.c)
+++ if_wb.c.fixed	(DF-4267 + DF-4268 + DF-4270 fixes)
@@ -906,7 +906,7 @@
 		cd->wb_rx_chain[i].wb_buf = &ld->wb_rxbufs[i];
 		if (wb_newbuf(sc, &cd->wb_rx_chain[i], NULL) == ENOBUFS)
 			return(ENOBUFS);
-		nexti = (WB_RX_LIST_CNT - 1) ? 0 : i + 1;
+		nexti = (i == WB_RX_LIST_CNT - 1) ? 0 : i + 1;
 		cd->wb_rx_chain[i].wb_nextdesc = &cd->wb_rx_chain[nexti];
 		ld->wb_rx_list[i].wb_next =  vtophys(&ld->wb_rx_list[nexti]);
 	}
@@ -980,8 +980,8 @@
 		m = cur_rx->wb_mbuf;
 
 		if ((rxstat & WB_RXSTAT_MIIERR) ||
-		    (WB_RXBYTES(cur_rx->wb_ptr->wb_status) < WB_MIN_FRAMELEN) ||
-		    (WB_RXBYTES(cur_rx->wb_ptr->wb_status) > 1536) ||
+		    (WB_RXBYTES(rxstat) < WB_MIN_FRAMELEN) ||
+		    (WB_RXBYTES(rxstat) > 1536) ||
 		    (rxstat & WB_RXSTAT_LASTFRAG) == 0||
 		    (rxstat & WB_RXSTAT_RXCMP) == 0) {
 			IFNET_STAT_INC(ifp, ierrors, 1);
@@ -1001,7 +1001,7 @@
 		}
 
 		/* No errors; receive the packet. */	
-		total_len = WB_RXBYTES(cur_rx->wb_ptr->wb_status);
+		total_len = WB_RXBYTES(rxstat);
 
 		/*
 		 * XXX The Winbond chip includes the CRC with every
@@ -1324,7 +1324,25 @@
 		sc->wb_cdata.wb_tx_free = cur_tx->wb_nextdesc;
 
 		/* Pack the data into the descriptor. */
-		wb_encap(sc, cur_tx, m_head);
+		if (wb_encap(sc, cur_tx, m_head) != 0) {
+			int fidx;
+
+			/*
+			 * wb_encap() failed (mbuf shortage): free the
+			 * dequeued packet, disarm the partially programmed
+			 * fragments so the NIC never walks the unterminated
+			 * chain, and put the descriptor back on the free
+			 * list.
+			 */
+			m_freem(m_head);
+			cur_tx->wb_mbuf = NULL;
+			for (fidx = 0; fidx < WB_MAXFRAGS; fidx++)
+				cur_tx->wb_ptr->wb_frag[fidx].wb_status = 0;
+			sc->wb_cdata.wb_tx_free = cur_tx;
+			if (cur_tx == start_tx)
+				return;		/* nothing was queued */
+			break;
+		}
 
 		if (cur_tx != start_tx)
 			WB_TXOWN(cur_tx) = WB_TXSTAT_OWN;