From c5cb9dd220ba9fdcf4ba485ce3d1d36ca32ac00b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 17 Jul 2026 17:31:05 +0300 Subject: [PATCH] wifi: iwlwifi: mld: validate wake packet crypto overhead Wake packet parsing only accounted for FCS and missed per-key IV/ICV overhead for protected data frames. Prevent size underflow and bad packet trimming when notifications are malformed or truncated. Signed-off-by: Emmanuel Grumbach Link: https://patch.msgid.link/20260717172958.e06595623533.Ie09494b7e34e5872b750fd90e325648ee469d0da@changeid Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/mld/d3.c | 63 +++++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index 3b785c53948f..301983428a63 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -59,6 +59,30 @@ struct iwl_mld_suspend_key_iter_data { __le32 bigtk_cipher; }; +struct iwl_mld_wake_pkt_iter_data { + bool multicast; + u32 ivlen; + u32 icvlen; +}; + +static void +iwl_mld_wake_pkt_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, void *_data) +{ + struct iwl_mld_wake_pkt_iter_data *data = _data; + bool is_group_key = !sta; + + /* ignore anything that is not a PTK / GTK */ + if (key->keyidx > 3) + return; + if (is_group_key != data->multicast) + return; + + data->ivlen = key->iv_len; + data->icvlen = key->icv_len; +} + struct iwl_mld_mcast_key_data { u8 key[WOWLAN_KEY_MAX_SIZE]; u8 len; @@ -743,11 +767,17 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld, struct cfg80211_wowlan_wakeup *wakeup, struct sk_buff **_pkt) { - int pkt_bufsize = wowlan_status->wake_packet_bufsize; - int expected_pktlen = wowlan_status->wake_packet_length; + u32 pkt_bufsize = wowlan_status->wake_packet_bufsize; + u32 expected_pktlen = wowlan_status->wake_packet_length; const u8 *pktdata = wowlan_status->wake_packet; const struct ieee80211_hdr *hdr = (const void *)pktdata; - int truncated = expected_pktlen - pkt_bufsize; + u32 truncated; + + if (IWL_FW_CHECK(mld, pkt_bufsize < sizeof(*hdr), + "pkt_bufsize is too short: %u\n", pkt_bufsize)) + return; + + truncated = expected_pktlen - pkt_bufsize; if (ieee80211_is_data(hdr->frame_control)) { int hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -758,9 +788,18 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld, if (!pkt) return; - skb_put_data(pkt, pktdata, hdrlen); - pktdata += hdrlen; - pkt_bufsize -= hdrlen; + if (ieee80211_has_protected(hdr->frame_control)) { + struct iwl_mld_wake_pkt_iter_data iter_data = { + .multicast = + is_multicast_ether_addr(hdr->addr1), + }; + + ieee80211_iter_keys(mld->hw, vif, + iwl_mld_wake_pkt_key_iter, + &iter_data); + ivlen = iter_data.ivlen; + icvlen += iter_data.icvlen; + } /* if truncated, FCS/ICV is (partially) gone */ if (truncated >= icvlen) { @@ -771,6 +810,13 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld, truncated = 0; } + if (IWL_FW_CHECK(mld, pkt_bufsize <= hdrlen + ivlen + icvlen, + "pkt_bufsize is too small %u\n", pkt_bufsize)) + return; + + skb_put_data(pkt, pktdata, hdrlen); + pktdata += hdrlen; + pkt_bufsize -= hdrlen; pkt_bufsize -= ivlen + icvlen; pktdata += ivlen; @@ -792,6 +838,11 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld, fcslen -= truncated; truncated = 0; } + + if (IWL_FW_CHECK(mld, pkt_bufsize <= fcslen, + "pkt_bufsize is too small %u\n", pkt_bufsize)) + return; + pkt_bufsize -= fcslen; wakeup->packet = wowlan_status->wake_packet; wakeup->packet_present_len = pkt_bufsize;