diff --git a/sys/dev/netif/wpi/if_wpi.c b/sys/dev/netif/wpi/if_wpi.c --- a/sys/dev/netif/wpi/if_wpi.c +++ b/sys/dev/netif/wpi/if_wpi.c @@ -1966,6 +1966,23 @@ bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); head = (struct wpi_rx_head *)((caddr_t)(stat + 1) + stat->len); len = le16toh(head->len); + + /* + * Upper-bound the firmware-reported frame length against the RX + * cluster before computing/dereferencing tail. `head` sits inside + * data->m's MJUMPAGESIZE (4096) DMA buffer; without this check a + * buggy or hostile firmware/PHY reporting len up to 65535 made + * (head + 1) + len -- and thus tail -- point past the 4KB cluster, + * dereferencing tail->flags (OOB heap read) and later setting + * m_len = len for an oversized ieee80211_input walk. Same class of + * fix as iwn (DF-1123). + */ + if ((caddr_t)(head + 1) + len + sizeof(struct wpi_rx_tail) > + mtod(data->m, caddr_t) + MJUMPAGESIZE) { + DPRINTF(sc, WPI_DEBUG_RECV, "%s: frame too long: %d\n", + __func__, len); + goto fail1; + } tail = (struct wpi_rx_tail *)((caddr_t)(head + 1) + len); flags = le32toh(tail->flags);