mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] wifi: mt76: validate mt792x firmware TLV payloads
@ 2026-10-28  5:07 Jiale Yao
  2026-10-28  5:07 ` [PATCH 1/3] wifi: mt76: mt7921: validate NIC capability payload lengths Jiale Yao
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Jiale Yao @ 2026-10-28  5:07 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
	Deren Wu, Nelson Yu, Mingyen Hsieh, Rong Yan, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek

The mt7921 and mt7925 firmware event parsers validate some outer skb
lengths, but several paths still trust type-specific lengths before
reading fixed fields. Malformed responses can make the drivers read past
a TLV payload, and a zero-length mt7925 capability TLV can stop progress
through the response.

Validate the fixed and type-specific payload extents before consuming
NIC capability and debug message data. Each patch covers one independent
parser and can be applied separately.

Jiale Yao (3):
  wifi: mt76: mt7921: validate NIC capability payload lengths
  wifi: mt76: mt7925: validate debug message lengths
  wifi: mt76: mt7925: validate NIC capability payload lengths

 .../net/wireless/mediatek/mt76/mt7921/mcu.c   | 41 +++++++++---
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   | 67 ++++++++++++++++---
 2 files changed, 90 insertions(+), 18 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] wifi: mt76: mt7921: validate NIC capability payload lengths
  2026-10-28  5:07 [PATCH 0/3] wifi: mt76: validate mt792x firmware TLV payloads Jiale Yao
@ 2026-10-28  5:07 ` Jiale Yao
  2026-10-28  5:07 ` [PATCH 2/3] wifi: mt76: mt7925: validate debug message lengths Jiale Yao
  2026-10-28  5:07 ` [PATCH 3/3] wifi: mt76: mt7925: validate NIC capability payload lengths Jiale Yao
  2 siblings, 0 replies; 4+ messages in thread
From: Jiale Yao @ 2026-10-28  5:07 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
	Deren Wu, linux-wireless, linux-kernel, linux-arm-kernel,
	linux-mediatek
  Cc: stable

The NIC capability parser checks that each declared payload fits in the
skb, but it does not ensure that the payload is large enough for the
selected capability. A truncated firmware response can therefore make
the driver read beyond the current TLV while copying fixed-size fields or
parsing capability structures.

Validate every consumed payload before accessing it and reject the
response when a known capability is shorter than its fixed data.

Fixes: dab35009fc1c ("wifi: mt76: mt7921: move connac nic capability handling to mt7921")
Cc: stable@vger.kernel.org
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
 .../net/wireless/mediatek/mt76/mt7921/mcu.c   | 41 +++++++++++++++----
 1 file changed, 33 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 25638c68c468..c960648b2b61 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -521,8 +521,8 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
 	return ret;
 }
 
-static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev,
-					 struct sk_buff *skb)
+static bool mt7921_mcu_parse_tx_resource(struct mt76_dev *dev,
+					 struct sk_buff *skb, int len)
 {
 	struct mt76_sdio *sdio = &dev->sdio;
 	struct mt7921_tx_resource {
@@ -537,6 +537,9 @@ static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev,
 		u8 pad[3];
 	} __packed * tx_res;
 
+	if (len < sizeof(*tx_res))
+		return false;
+
 	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);
@@ -546,10 +549,12 @@ static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev,
 	sdio->sched.ple_data_quota = le32_to_cpu(tx_res->ple_data_quota);
 	sdio->sched.pse_page_size = le16_to_cpu(tx_res->pse_page_size);
 	sdio->sched.deficit = tx_res->pp_padding;
+
+	return true;
 }
 
-static void mt7921_mcu_parse_phy_cap(struct mt76_dev *dev,
-				     struct sk_buff *skb)
+static bool mt7921_mcu_parse_phy_cap(struct mt76_dev *dev,
+				     struct sk_buff *skb, int len)
 {
 	struct mt7921_phy_cap {
 		u8 ht;
@@ -571,12 +576,17 @@ static void mt7921_mcu_parse_phy_cap(struct mt76_dev *dev,
 		WF0_5G
 	};
 
+	if (len < sizeof(*cap))
+		return false;
+
 	cap = (struct mt7921_phy_cap *)skb->data;
 
 	dev->phy.antenna_mask = BIT(cap->nss) - 1;
 	dev->phy.chainmask = dev->phy.antenna_mask;
 	dev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G);
 	dev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G);
+
+	return true;
 }
 
 static int mt7921_mcu_get_nic_capability(struct mt792x_phy *mphy)
@@ -620,20 +630,30 @@ static int mt7921_mcu_get_nic_capability(struct mt792x_phy *mphy)
 
 		switch (le32_to_cpu(tlv->type)) {
 		case MT_NIC_CAP_6G:
+			if (len < sizeof(skb->data[0]))
+				goto invalid;
+
 			phy->cap.has_6ghz = skb->data[0];
 			break;
 		case MT_NIC_CAP_MAC_ADDR:
+			if (len < ETH_ALEN)
+				goto invalid;
+
 			memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN);
 			break;
 		case MT_NIC_CAP_PHY:
-			mt7921_mcu_parse_phy_cap(phy->dev, skb);
+			if (!mt7921_mcu_parse_phy_cap(phy->dev, skb, len))
+				goto invalid;
 			break;
 		case MT_NIC_CAP_TX_RESOURCE:
-			if (mt76_is_sdio(phy->dev))
-				mt7921_mcu_parse_tx_resource(phy->dev,
-							     skb);
+			if (mt76_is_sdio(phy->dev) &&
+			    !mt7921_mcu_parse_tx_resource(phy->dev, skb, len))
+				goto invalid;
 			break;
 		case MT_NIC_CAP_CHIP_CAP:
+			if (len < sizeof(mphy->chip_cap))
+				goto invalid;
+
 			memcpy(&mphy->chip_cap, (void *)skb->data, sizeof(u64));
 			break;
 		default:
@@ -641,6 +661,11 @@ static int mt7921_mcu_get_nic_capability(struct mt792x_phy *mphy)
 		}
 		skb_pull(skb, len);
 	}
+
+	goto out;
+
+invalid:
+	ret = -EINVAL;
 out:
 	dev_kfree_skb(skb);
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/3] wifi: mt76: mt7925: validate debug message lengths
  2026-10-28  5:07 [PATCH 0/3] wifi: mt76: validate mt792x firmware TLV payloads Jiale Yao
  2026-10-28  5:07 ` [PATCH 1/3] wifi: mt76: mt7921: validate NIC capability payload lengths Jiale Yao
@ 2026-10-28  5:07 ` Jiale Yao
  2026-10-28  5:07 ` [PATCH 3/3] wifi: mt76: mt7925: validate NIC capability payload lengths Jiale Yao
  2 siblings, 0 replies; 4+ messages in thread
From: Jiale Yao @ 2026-10-28  5:07 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
	Mingyen Hsieh, Quan Zhou, Deren Wu, Leon Yen, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: stable

The debug message event handler removes the event prefix and accesses the
message header without checking the skb length. It also subtracts the
fixed header from the firmware-provided length without checking for an
underflow and trusts the string length. A truncated event can therefore
cause out-of-bounds reads while formatting firmware logs.

Validate the event prefix, fixed fields, declared message extent and each
format-specific payload before reading them.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Cc: stable@vger.kernel.org
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   | 24 +++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 26cdb3f0a98a..c612fda55eb7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -596,8 +596,14 @@ mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
 			} __packed txt;
 		};
 	} __packed * hdr;
+	u16 msg_len;
 
+	if (skb->len < sizeof(struct mt7925_mcu_rxd) + 4)
+		return;
 	skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);
+	if (skb->len < offsetof(struct mt7925_uni_debug_msg, idx))
+		return;
+
 	hdr = (struct mt7925_uni_debug_msg *)skb->data;
 
 	if (hdr->id == 0x28) {
@@ -608,19 +614,28 @@ mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
 		return;
 	}
 
+	msg_len = le16_to_cpu(hdr->len);
+	if (msg_len < offsetof(struct mt7925_uni_debug_msg, idx) ||
+	    msg_len > skb->len)
+		return;
+
 	if (hdr->type == 0) { /* idx log */
 		int i, ret, len = PAGE_SIZE - 1, nr_val;
-		struct page *page = dev_alloc_pages(get_order(len));
+		struct page *page;
 		__le32 *val;
 		char *buf, *cur;
 
+		if (msg_len < sizeof(*hdr))
+			return;
+
+		page = dev_alloc_pages(get_order(len));
 		if (!page)
 			return;
 
 		buf = page_address(page);
 		cur = buf;
 
-		nr_val = (le16_to_cpu(hdr->len) - sizeof(*hdr)) / 4;
+		nr_val = (msg_len - sizeof(*hdr)) / sizeof(*val);
 		val = (__le32 *)hdr->idx.data;
 		for (i = 0; i < nr_val && len > 0; i++) {
 			ret = snprintf(cur, len, "0x%x,", le32_to_cpu(val[i]));
@@ -635,6 +650,11 @@ mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
 				   le32_to_cpu(hdr->idx.idx), nr_val, buf);
 		put_page(page);
 	} else if (hdr->type == 2) { /* str log */
+		if (msg_len < offsetof(struct mt7925_uni_debug_msg, txt.data) ||
+		    hdr->txt.len > msg_len - offsetof(struct mt7925_uni_debug_msg,
+						       txt.data))
+			return;
+
 		wiphy_info(mt76_hw(dev)->wiphy, "%.*s", hdr->txt.len, hdr->txt.data);
 	}
 }
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 3/3] wifi: mt76: mt7925: validate NIC capability payload lengths
  2026-10-28  5:07 [PATCH 0/3] wifi: mt76: validate mt792x firmware TLV payloads Jiale Yao
  2026-10-28  5:07 ` [PATCH 1/3] wifi: mt76: mt7921: validate NIC capability payload lengths Jiale Yao
  2026-10-28  5:07 ` [PATCH 2/3] wifi: mt76: mt7925: validate debug message lengths Jiale Yao
@ 2026-10-28  5:07 ` Jiale Yao
  2 siblings, 0 replies; 4+ messages in thread
From: Jiale Yao @ 2026-10-28  5:07 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
	Leon Yen, Quan Zhou, Rong Yan, Hao Zhang, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: stable

The NIC capability parser only checks whether a declared TLV length fits
in the skb. It does not reject lengths shorter than the TLV header or
ensure that known payloads contain the fields consumed by the driver. A
truncated firmware response can therefore stall the parser on a zero
length TLV or cause out-of-bounds reads from fixed-size payloads.

Reject undersized TLVs and validate every known payload before accessing
it.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Cc: stable@vger.kernel.org
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   | 43 +++++++++++++++----
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index c612fda55eb7..41138203ada2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1039,8 +1039,8 @@ int mt7925_mcu_get_temperature(struct mt792x_phy *phy)
 	return temperature;
 }
 
-static void
-mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data)
+static bool
+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;
@@ -1064,16 +1064,21 @@ mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data)
 		WF0_5G
 	};
 
+	if (len < sizeof(*cap))
+		return false;
+
 	cap = (struct mt7925_mcu_phy_cap *)data;
 
 	mdev->phy.antenna_mask = BIT(cap->nss) - 1;
 	mdev->phy.chainmask = mdev->phy.antenna_mask;
 	mdev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G);
 	mdev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G);
+
+	return true;
 }
 
-static void
-mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data)
+static bool
+mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data, int len)
 {
 	struct mt7925_mcu_eml_cap {
 		u8 rsv[4];
@@ -1081,9 +1086,14 @@ mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data)
 		u8 rsv2[6];
 	} __packed * cap;
 
+	if (len < sizeof(*cap))
+		return false;
+
 	cap = (struct mt7925_mcu_eml_cap *)data;
 
 	dev->phy.eml_cap = le16_to_cpu(cap->eml_cap);
+
+	return true;
 }
 
 static int
@@ -1121,36 +1131,53 @@ 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 data_len, 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:
+			if (len < sizeof(*tlv) + sizeof(tlv->data[0]))
+				goto invalid;
+
 			mphy->cap.has_6ghz = !!tlv->data[0];
 			break;
 		case MT_NIC_CAP_MAC_ADDR:
+			if (len < sizeof(*tlv) + ETH_ALEN)
+				goto invalid;
+
 			memcpy(mphy->macaddr, (void *)tlv->data, ETH_ALEN);
 			break;
 		case MT_NIC_CAP_PHY:
-			mt7925_mcu_parse_phy_cap(dev, tlv->data);
+			if (!mt7925_mcu_parse_phy_cap(dev, tlv->data, data_len))
+				goto invalid;
 			break;
 		case MT_NIC_CAP_CHIP_CAP:
+			if (len < sizeof(*tlv) + sizeof(__le64))
+				goto invalid;
+
 			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);
+			if (!mt7925_mcu_parse_eml_cap(dev, tlv->data, data_len))
+				goto invalid;
 			break;
 		default:
 			break;
 		}
 		skb_pull(skb, len);
 	}
+
+	goto out;
+
+invalid:
+	ret = -EINVAL;
 out:
 	dev_kfree_skb(skb);
 	return ret;
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-28  5:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-28  5:07 [PATCH 0/3] wifi: mt76: validate mt792x firmware TLV payloads Jiale Yao
2026-10-28  5:07 ` [PATCH 1/3] wifi: mt76: mt7921: validate NIC capability payload lengths Jiale Yao
2026-10-28  5:07 ` [PATCH 2/3] wifi: mt76: mt7925: validate debug message lengths Jiale Yao
2026-10-28  5:07 ` [PATCH 3/3] wifi: mt76: mt7925: validate NIC capability payload lengths Jiale Yao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®