diff --git a/sys/dev/netif/iwn/if_iwn.c b/sys/dev/netif/iwn/if_iwn.c --- a/sys/dev/netif/iwn/if_iwn.c +++ b/sys/dev/netif/iwn/if_iwn.c @@ -3081,6 +3081,27 @@ len = le16toh(stat->len); } + /* + * Upper-bound the firmware-reported frame length against the RX + * cluster. `head` sits inside data->m's IWN_RBUF_SIZE (4096) DMA + * buffer, and the FCS read below dereferences (head + len). Without + * this check a buggy or hostile firmware/PHY reporting len up to 65535 + * read ~60KB past the 4KB cluster (OOB heap read) and fabricated an + * mbuf claiming that oversized body for ieee80211_input. + */ + if (len > IWN_RBUF_SIZE || + (vm_offset_t)(head + len + sizeof(uint32_t)) > + (vm_offset_t)mtod(data->m, caddr_t) + IWN_RBUF_SIZE) { + DPRINTF(sc, IWN_DEBUG_RECV, "%s: frame too long: %d\n", + __func__, len); +#if defined(__DragonFly__) + ++ic->ic_ierrors; +#else + counter_u64_add(ic->ic_ierrors, 1); +#endif + return; + } + flags = le32toh(*(uint32_t *)(head + len)); /* Discard frames with a bad FCS early. */