mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 08:15:07 -04:00
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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user