DragonFlyBSD Kernel Audit
DF-1145 / fix.diff
← back to finding ↓ download raw
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;