⬢ DragonFlyBSD Kernel Audit
DF-4232 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/netif/txp/if_txp.c
+++ b/sys/dev/netif/txp/if_txp.c
@@ -657,6 +657,22 @@
 
 	roff = *r->r_roff;
 	woff = *r->r_woff;
+
+	/*
+	 * The ring cursors are firmware-fed DMA state (DF-4232).  Validate
+	 * them against the ring geometry before walking anything: both must
+	 * be descriptor-aligned and inside the ring, else the descriptor
+	 * walk runs off the ring (wild rx_sd deref) or never terminates.
+	 */
+	if (((roff | woff) & (sizeof(struct txp_rx_desc) - 1)) != 0 ||
+	    roff >= (RX_ENTRIES * sizeof(struct txp_rx_desc)) ||
+	    woff >= (RX_ENTRIES * sizeof(struct txp_rx_desc))) {
+		if_printf(ifp, "invalid rx ring indices 0x%x/0x%x\n", roff, woff);
+		IFNET_STAT_INC(ifp, ierrors, 1);
+		*r->r_roff = *r->r_woff = 0;
+		return;
+	}
+
 	rxd = r->r_desc + (roff / sizeof(struct txp_rx_desc));
 
 	while (roff != woff) {
@@ -1415,6 +1431,21 @@
 	struct txp_hostvar *hv = sc->sc_hostvar;
 	struct txp_rsp_desc *rsp;
 
+	/*
+	 * Response-ring cursors are firmware-fed DMA state (DF-4232):
+	 * validate before computing rsp = base + ridx, and never loop on a
+	 * write index that no aligned walk can ever reach.
+	 */
+	if ((ridx & (sizeof(struct txp_rsp_desc) - 1)) != 0 ||
+	    ridx >= sc->sc_rspring.size ||
+	    (hv->hv_resp_write_idx & (sizeof(struct txp_rsp_desc) - 1)) != 0 ||
+	    hv->hv_resp_write_idx >= sc->sc_rspring.size) {
+		if_printf(&sc->sc_arpcom.ac_if, "invalid response indices "
+		    "0x%x/0x%x\n", ridx, hv->hv_resp_write_idx);
+		hv->hv_resp_read_idx = hv->hv_resp_write_idx = 0;
+		return (-1);
+	}
+
 	while (ridx != hv->hv_resp_write_idx) {
 		rsp = (struct txp_rsp_desc *)(((u_int8_t *)sc->sc_rspring.base) + ridx);