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 <emmanuel.grumbach@intel.com>
Link: https://patch.msgid.link/20260717172958.e06595623533.Ie09494b7e34e5872b750fd90e325648ee469d0da@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
This commit is contained in:
Emmanuel Grumbach 2026-07-17 17:31:05 +03:00 committed by Miri Korenblit
parent 905f57aefd
commit c5cb9dd220

View File

@ -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;