DF-1145 / fix.diff
diff --git a/sys/dev/netif/iwm/if_iwm.c b/sys/dev/netif/iwm/if_iwm.c --- a/sys/dev/netif/iwm/if_iwm.c +++ b/sys/dev/netif/iwm/if_iwm.c @@ -3099,6 +3099,9 @@ IWM_DPRINTF(sc, IWM_DEBUG_RECV, "received PHY stats\n"); + if (iwm_rx_packet_payload_len(pkt) < sizeof(sc->sc_last_phy_info)) + return; + memcpy(&sc->sc_last_phy_info, phy_info, sizeof(sc->sc_last_phy_info)); } @@ -3146,6 +3149,9 @@ { struct iwm_notif_statistics *stats = (void *)&pkt->data; + if (iwm_rx_packet_payload_len(pkt) < sizeof(sc->sc_stats)) + return; + memcpy(&sc->sc_stats, stats, sizeof(sc->sc_stats)); sc->sc_noise = iwm_get_noise(sc, &stats->rx.general); } @@ -3219,6 +3225,14 @@ phy_info = &sc->sc_last_phy_info; rx_res = (struct iwm_rx_mpdu_res_start *)pkt->data; len = le16toh(rx_res->byte_count); + /* + * The firmware-supplied byte_count is untrusted and must fit within + * the actual received packet payload, otherwise the status-word read + * below (and the later m_len assignment) would read past the cluster. + */ + if (sizeof(*rx_res) + len + sizeof(uint32_t) > + iwm_rx_packet_payload_len(pkt)) + return false; rx_pkt_status = le32toh(*(uint32_t *)(pkt->data + sizeof(*rx_res) + len)); if (__predict_false(phy_info->cfg_phy_cnt > 20)) { @@ -3340,6 +3354,9 @@ channel = desc->v1.channel; len = le16toh(desc->mpdu_len); + /* The firmware-supplied mpdu_len is untrusted; bound it to the payload. */ + if (sizeof(*desc) + len > iwm_rx_packet_payload_len(pkt)) + return false; phy_info = le16toh(desc->phy_info); rate_n_flags = desc->v1.rate_n_flags; |