mt7925_mcu_get_nic_capability() checks that each TLV fits in the response, but not that the TLV is long enough for its own header or for the fields read from it. A short chip capability TLV at the end of the response causes an out-of-bounds read of its eight-byte value. A TLV length below the header size makes the loop parse overlapping TLVs. Stop at a TLV shorter than its header, and skip a TLV that is too short for the fields its parser reads, like mt7921 does. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Fixes: 86c051f2c418 ("wifi: mt76: mt7925: enabling MLO when the firmware supports it") Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index f299a3379adb..d26b90ab5e60 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1058,7 +1058,7 @@ int mt7925_mcu_get_temperature(struct mt792x_phy *phy) } static void -mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data) +mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data, int len) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_dev *mdev = mphy->dev; @@ -1082,6 +1082,9 @@ mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data) WF0_5G }; + if (len < offsetofend(struct mt7925_mcu_phy_cap, hw_path)) + return; + cap = (struct mt7925_mcu_phy_cap *)data; mdev->phy.antenna_mask = BIT(cap->nss) - 1; @@ -1091,7 +1094,7 @@ mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data) } static void -mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data) +mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data, int len) { struct mt7925_mcu_eml_cap { u8 rsv[4]; @@ -1099,6 +1102,9 @@ mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data) u8 rsv2[6]; } __packed * cap; + if (len < offsetofend(struct mt7925_mcu_eml_cap, eml_cap)) + return; + cap = (struct mt7925_mcu_eml_cap *)data; dev->phy.eml_cap = le16_to_cpu(cap->eml_cap); @@ -1139,30 +1145,35 @@ mt7925_mcu_get_nic_capability(struct mt792x_dev *dev) for (i = 0; i < le16_to_cpu(hdr->n_element); i++) { struct tlv *tlv = (struct tlv *)skb->data; - int len; + int len, data_len; if (skb->len < sizeof(*tlv)) break; len = le16_to_cpu(tlv->len); - if (skb->len < len) + if (len < sizeof(*tlv) || skb->len < len) break; + data_len = len - sizeof(*tlv); switch (le16_to_cpu(tlv->tag)) { case MT_NIC_CAP_6G: - mphy->cap.has_6ghz = !!tlv->data[0]; + if (data_len) + mphy->cap.has_6ghz = !!tlv->data[0]; break; case MT_NIC_CAP_MAC_ADDR: - memcpy(mphy->macaddr, (void *)tlv->data, ETH_ALEN); + if (data_len >= ETH_ALEN) + memcpy(mphy->macaddr, (void *)tlv->data, ETH_ALEN); break; case MT_NIC_CAP_PHY: - mt7925_mcu_parse_phy_cap(dev, tlv->data); + mt7925_mcu_parse_phy_cap(dev, tlv->data, data_len); break; case MT_NIC_CAP_CHIP_CAP: - dev->phy.chip_cap = le64_to_cpu(*(__le64 *)tlv->data); + if (data_len >= sizeof(__le64)) + dev->phy.chip_cap = + le64_to_cpu(*(__le64 *)tlv->data); break; case MT_NIC_CAP_EML_CAP: - mt7925_mcu_parse_eml_cap(dev, tlv->data); + mt7925_mcu_parse_eml_cap(dev, tlv->data, data_len); break; default: break; -- 2.47.3