[PATCH 3/7] wifi: mt76: mt7996: validate EEPROM response lengths

Jiale Yao yaojiale02 at 163.com
Mon Oct 19 19:49:29 PDT 2026


The EEPROM query reads fixed event fields and copies EFUSE or external
EEPROM data without checking the firmware response length. A truncated
response or an oversized external data length can cause out-of-bounds
reads.

Validate the fixed event, the requested EFUSE bytes, and both the
external data-length field and its payload before copying data.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Fixes: f456e1f56c4c ("wifi: mt76: add external EEPROM support for mt799x chipsets")
Signed-off-by: Jiale Yao <yaojiale02 at 163.com>
---
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   | 30 +++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 1f7af6359dd7..eb868c2d5108 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -4399,6 +4399,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l
 	};
 	struct mt7996_mcu_eeprom_access_event *event;
 	struct sk_buff *skb;
+	size_t data_offset;
 	int ret, cmd;
 	u32 addr;
 
@@ -4424,9 +4425,14 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l
 	if (ret)
 		return ret;
 
+	data_offset = offsetof(struct mt7996_mcu_eeprom_access_event, eeprom);
+	if (skb->len < data_offset) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	event = (struct mt7996_mcu_eeprom_access_event *)skb->data;
 	if (event->valid) {
-		u32 ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len);
 		u32 block = mode == EEPROM_MODE_EXT ? MT7996_EXT_EEPROM_BLOCK_SIZE :
 						      MT7996_EEPROM_BLOCK_SIZE;
 
@@ -4444,16 +4450,35 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l
 		case EEPROM_MODE_EFUSE:
 			if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE)
 				buf_len = MT7996_EEPROM_BLOCK_SIZE;
+			if (skb->len - data_offset < buf_len) {
+				ret = -EINVAL;
+				break;
+			}
 
 			memcpy(buf, event->eeprom.efuse, buf_len);
 			break;
-		case EEPROM_MODE_EXT:
+		case EEPROM_MODE_EXT: {
+			u32 ret_len;
+
+			if (skb->len - data_offset < sizeof(__le32)) {
+				ret = -EINVAL;
+				break;
+			}
+
+			ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len);
+			data_offset += sizeof(__le32);
+			if (ret_len > skb->len - data_offset) {
+				ret = -EINVAL;
+				break;
+			}
+
 			if (!buf_len || buf_len > MT7996_EXT_EEPROM_BLOCK_SIZE)
 				buf_len = MT7996_EXT_EEPROM_BLOCK_SIZE;
 
 			memcpy(buf, event->eeprom.ext_eeprom.data,
 			       ret_len < buf_len ? ret_len : buf_len);
 			break;
+		}
 		default:
 			ret = -EINVAL;
 			break;
@@ -4462,6 +4487,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l
 		ret = -EINVAL;
 	}
 
+out:
 	dev_kfree_skb(skb);
 
 	return ret;
-- 
2.34.1




More information about the Linux-mediatek mailing list