DragonFlyBSD Kernel Audit
DF-1221 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/virtual/amazon/ena/ena.c b/sys/dev/virtual/amazon/ena/ena.c
--- a/sys/dev/virtual/amazon/ena/ena.c
+++ b/sys/dev/virtual/amazon/ena/ena.c
@@ -1456,6 +1456,18 @@
 
 	len = ena_bufs[buf].len;
 	req_id = ena_bufs[buf].req_id;
+	/*
+	 * req_id is a 16-bit value supplied by the device/hypervisor.
+	 * rx_buffer_info is sized ring_size (<= 1024); an out-of-range
+	 * req_id indexes up to ~4 MB past the array into kernel heap,
+	 * yielding a garbage mbuf pointer dereferenced below.
+	 * validate_rx_req_id() exists for this (logs, bumps ierrors,
+	 * schedules a device reset) but was not called on the RX-consume
+	 * path unlike TX-consume and RX-refill.  NULL return makes the
+	 * caller release the descriptors and abort the packet.
+	 */
+	if (unlikely(validate_rx_req_id(rx_ring, req_id)))
+		return (NULL);
 	rx_info = &rx_ring->rx_buffer_info[req_id];
 
 	ena_trace(ENA_DBG | ENA_RXPTH, "rx_info %p, mbuf %p, paddr %jx",
@@ -1488,6 +1500,10 @@
 		++buf;
 		len = ena_bufs[buf].len;
 		req_id = ena_bufs[buf].req_id;
+		if (unlikely(validate_rx_req_id(rx_ring, req_id))) {
+			m_freem(mbuf);
+			return (NULL);
+		}
 		rx_info = &rx_ring->rx_buffer_info[req_id];
 
 		if (unlikely(rx_info->mbuf == NULL)) {