mt7921_mcu_get_nic_capability() checks that each TLV fits in the response, but not that the TLV is long enough for the fields read from it. A short TLV at the end of the response causes an out-of-bounds read, for example of the eight-byte chip capability. Skip a TLV that is too short for the fields its parser reads. Fixes: f7d2958ca461 ("mt76: connac: add mt76_connac_mcu_get_nic_capability utility routine") Fixes: 8c94f0e63bb3 ("mt76: connac: extend mcu_get_nic_capability") Fixes: 4fc8df50fd41 ("wifi: mt76: mt7921: get regulatory information from the clc event") Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 79fead3ccce1..9b2fa1db7642 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -546,7 +546,7 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) } static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev, - struct sk_buff *skb) + struct sk_buff *skb, int len) { struct mt76_sdio *sdio = &dev->sdio; struct mt7921_tx_resource { @@ -561,6 +561,9 @@ static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev, u8 pad[3]; } __packed * tx_res; + if (len < offsetofend(struct mt7921_tx_resource, pp_padding)) + return; + tx_res = (struct mt7921_tx_resource *)skb->data; sdio->sched.pse_data_quota = le32_to_cpu(tx_res->pse_data_quota); sdio->pse_mcu_quota_max = le32_to_cpu(tx_res->pse_mcu_quota); @@ -573,7 +576,7 @@ static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev, } static void mt7921_mcu_parse_phy_cap(struct mt76_dev *dev, - struct sk_buff *skb) + struct sk_buff *skb, int len) { struct mt7921_phy_cap { u8 ht; @@ -595,6 +598,9 @@ static void mt7921_mcu_parse_phy_cap(struct mt76_dev *dev, WF0_5G }; + if (len < offsetofend(struct mt7921_phy_cap, hw_path)) + return; + cap = (struct mt7921_phy_cap *)skb->data; dev->phy.antenna_mask = BIT(cap->nss) - 1; @@ -644,21 +650,25 @@ static int mt7921_mcu_get_nic_capability(struct mt792x_phy *mphy) switch (le32_to_cpu(tlv->type)) { case MT_NIC_CAP_6G: - phy->cap.has_6ghz = skb->data[0]; + if (len) + phy->cap.has_6ghz = skb->data[0]; break; case MT_NIC_CAP_MAC_ADDR: - memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN); + if (len >= ETH_ALEN) + memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN); break; case MT_NIC_CAP_PHY: - mt7921_mcu_parse_phy_cap(phy->dev, skb); + mt7921_mcu_parse_phy_cap(phy->dev, skb, len); break; case MT_NIC_CAP_TX_RESOURCE: if (mt76_is_sdio(phy->dev)) mt7921_mcu_parse_tx_resource(phy->dev, - skb); + skb, len); break; case MT_NIC_CAP_CHIP_CAP: - memcpy(&mphy->chip_cap, (void *)skb->data, sizeof(u64)); + if (len >= sizeof(u64)) + memcpy(&mphy->chip_cap, (void *)skb->data, + sizeof(u64)); break; default: break; -- 2.47.3