[PATCH 2/7] wifi: mt76: mt7996: bound IE countdown event parsing
From: Jiale Yao
Date: Mon Oct 19 2026 - 22:51:13 EST
The IE countdown handler reads its fixed header before checking the skb
length. Its TLV loop also accepts lengths smaller than the TLV header or
larger than the remaining data and reads the event payload unchecked.
Validate the fixed fields and constrain every TLV and known countdown
payload to the response buffer.
Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Signed-off-by: Jiale Yao <yaojiale02@xxxxxxx>
---
.../net/wireless/mediatek/mt76/mt7996/mcu.c | 38 ++++++++++++++-----
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index d661ff1e4a20..1f7af6359dd7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -489,12 +489,20 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
u8 band;
u8 rsv[3];
};
- struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
- const char *data = (char *)&rxd[1], *tail;
- struct header *hdr = (struct header *)data;
- struct tlv *tlv = (struct tlv *)(data + 4);
+ struct mt7996_mcu_rxd *rxd;
+ const char *data, *tail;
+ struct header *hdr;
+ struct tlv *tlv;
struct mt7996_mcu_countdown_notify *event;
struct mt7996_mcu_countdown_data cdata;
+ u16 tlv_len;
+
+ if (skb->len < sizeof(*rxd) + sizeof(*hdr))
+ return;
+
+ rxd = (struct mt7996_mcu_rxd *)skb->data;
+ data = (char *)&rxd[1];
+ hdr = (struct header *)data;
if (hdr->band >= ARRAY_SIZE(dev->mt76.phys))
return;
@@ -505,18 +513,29 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
tail = skb->data + skb->len;
data += sizeof(*hdr);
- while (data + sizeof(*tlv) < tail && le16_to_cpu(tlv->len)) {
- event = (struct mt7996_mcu_countdown_notify *)tlv->data;
-
- cdata.omac_idx = event->omac_idx;
+ while (tail - data >= sizeof(*tlv)) {
+ tlv = (struct tlv *)data;
+ tlv_len = le16_to_cpu(tlv->len);
+ if (tlv_len < sizeof(*tlv) || tlv_len > tail - data)
+ return;
switch (le16_to_cpu(tlv->tag)) {
case UNI_EVENT_IE_COUNTDOWN_CSA:
+ if (tlv_len < sizeof(*tlv) + sizeof(*event))
+ return;
+
+ event = (struct mt7996_mcu_countdown_notify *)tlv->data;
+ cdata.omac_idx = event->omac_idx;
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7996_mcu_csa_finish, &cdata);
break;
case UNI_EVENT_IE_COUNTDOWN_BCC:
+ if (tlv_len < sizeof(*tlv) + sizeof(*event))
+ return;
+
+ event = (struct mt7996_mcu_countdown_notify *)tlv->data;
+ cdata.omac_idx = event->omac_idx;
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7996_mcu_cca_finish, &cdata);
@@ -525,8 +544,7 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
break;
}
- data += le16_to_cpu(tlv->len);
- tlv = (struct tlv *)data;
+ data += tlv_len;
}
}
--
2.34.1