[PATCH] wifi: mt76: mt7615: validate MCU response lengths
From: Pengpeng Hou <hidden>
Date: 2026-08-30 13:10:58
Also in:
linux-mediatek, linux-wireless, lkml
Subsystem:
mediatek mt76 wireless lan driver, the rest · Maintainers:
Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Linus Torvalds
mt7615_mcu_parse_response() reads the common response header before
checking its size and then consumes command-specific fields after unchecked
skb_pull() calls. A short firmware response can therefore be read beyond
its current extent.
Validate the common header and each command-specific payload before reading
it.
Fixes: 0e6a29e477f3 ("mt76: mt7615: add support to read temperature from mcu")
Signed-off-by: Pengpeng Hou <redacted>
---
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index ff57ede87f717..084949dd3e94e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c@@ -143,18 +143,26 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd, cmd, seq); return -ETIMEDOUT; } + if (skb->len < sizeof(*rxd)) + return -EMSGSIZE; rxd = (struct mt7615_mcu_rxd *)skb->data; if (seq != rxd->seq) return -EAGAIN; if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { + if (skb->len < sizeof(*rxd) - 4 + sizeof(skb->data[0])) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { + if (skb->len < sizeof(*rxd) + sizeof(__le32)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)skb->data); } else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) { + if (skb->len < sizeof(*rxd) + 8 + sizeof(__le32)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)&skb->data[8]); } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
@@ -165,12 +173,16 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd, cmd == MCU_UNI_CMD(SUSPEND)) { struct mt76_connac_mcu_uni_event *event; + if (skb->len < sizeof(*rxd) + sizeof(*event)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); } else if (cmd == MCU_CE_QUERY(REG_READ)) { struct mt76_connac_mcu_reg_event *event; + if (skb->len < sizeof(*rxd) + sizeof(*event)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_reg_event *)skb->data; ret = (int)le32_to_cpu(event->val);
base-commit: 08dbfad3f5040f5bdb6c529da20d6d4e81fefd72 -- 2.50.1