mt76_connac2_load_patch() only checks that the patch image holds the header. The section table after the header, and the offset and length of each section, come from the image and are not checked against its size. A malformed image makes the driver read past the image and send that data to the device. Add mt76_connac2_patch_check(), which checks that the section table and every section fit in the image, and reject an image that fails it. Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Fixes: 1c099ab44727 ("mt76: mt7921: add MCU support") Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 29 ++++++++++++++++++- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 88cdc8083bae..ad53bb60d5cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -3305,6 +3305,33 @@ static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info) return mode; } +int mt76_connac2_patch_check(const struct firmware *fw) +{ + const struct mt76_connac2_patch_hdr *hdr; + const struct mt76_connac2_patch_sec *sec; + u32 i, n_region; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) + return -EINVAL; + + hdr = (const void *)fw->data; + n_region = be32_to_cpu(hdr->desc.n_region); + if (n_region > (fw->size - sizeof(*hdr)) / sizeof(*sec)) + return -EINVAL; + + sec = (const void *)(fw->data + sizeof(*hdr)); + for (i = 0; i < n_region; i++) { + u32 offs = be32_to_cpu(sec[i].offs); + u32 len = be32_to_cpu(sec[i].info.len); + + if (offs > fw->size || len > fw->size - offs) + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac2_patch_check); + int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) { int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096; @@ -3326,7 +3353,7 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) if (ret) goto out; - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + if (mt76_connac2_patch_check(fw)) { dev_err(dev->dev, "Invalid firmware\n"); ret = -EINVAL; goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 755c83f95f27..88281733a3df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -2153,6 +2153,7 @@ int mt76_connac2_fw_check(const struct firmware *fw, size_t *data_len); int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, const char *fw_wa); int mt76_connac3_load_phy_ram(struct mt76_dev *dev, const char *fw_name); +int mt76_connac2_patch_check(const struct firmware *fw); int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name); int mt76_connac3_load_cb_patch(struct mt76_dev *dev, const char *fw_name); int mt76_connac2_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, -- 2.47.3