wifi: mt76: mt7996: bound TLV walk in mt7996_mcu_get_chip_config

The response TLV loop advanced by tlv->len without a minimum, so a
theoretical firmware response containing a zero-length TLV could spin
forever, hanging the CPU during device probe.
The u32 payload was also read without bounds checking.
Reject a short fixed field, stop on a TLV whose length underruns the
header or overruns the skb.

Fixes: 5d33053be6 ("wifi: mt76: mt7996: add variants support")
Link: https://patch.msgid.link/20260724124813.3961474-2-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Felix Fietkau
2026-07-24 12:47:46 +00:00
parent cbeed70967
commit 44af52467e

View File

@@ -4445,21 +4445,31 @@ int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap)
return ret;
/* fixed field */
if (skb->len < 4) {
dev_kfree_skb(skb);
return -EINVAL;
}
skb_pull(skb, 4);
buf = skb->data;
while (buf - skb->data < skb->len) {
while (buf - skb->data + sizeof(struct tlv) <= skb->len) {
struct tlv *tlv = (struct tlv *)buf;
u16 tlv_len = le16_to_cpu(tlv->len);
if (tlv_len < sizeof(*tlv) ||
tlv_len > skb->len - (buf - skb->data))
break;
switch (le16_to_cpu(tlv->tag)) {
case UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION:
*cap = le32_to_cpu(*(__le32 *)(buf + sizeof(*tlv)));
if (tlv_len >= sizeof(*tlv) + sizeof(__le32))
*cap = le32_to_cpu(*(__le32 *)(buf + sizeof(*tlv)));
break;
default:
break;
}
buf += le16_to_cpu(tlv->len);
buf += tlv_len;
}
dev_kfree_skb(skb);