[PATCH 11/11] wifi: mt76: mt792x: bound firmware release-info parsing

Jiale Yao yaojiale02 at 163.com
Mon Oct 19 19:46:44 PDT 2026


mt792x_get_offload_capability() derives region and release-info pointers
from firmware-provided counts and lengths without keeping them within
the firmware image. A malformed image can therefore cause out-of-bounds
reads while locating or walking the feature records.

Validate the region table, accumulated region lengths, release-info
range, each record, its padding, and the feature payload before reading
them.

Fixes: e8a264ccd2de ("wifi: mt76: mt7921: move init shared code in mt792x-lib module")
Signed-off-by: Jiale Yao <yaojiale02 at 163.com>
---
 .../net/wireless/mediatek/mt76/mt792x_core.c  | 44 ++++++++++++++++---
 1 file changed, 38 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
index 0ad33f74c228..feab3abcc1dc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
@@ -862,9 +862,10 @@ mt792x_get_offload_capability(struct device *dev, const char *fw_wm)
 {
 	const struct mt76_connac2_fw_trailer *hdr;
 	struct mt792x_realease_info *rel_info;
+	const u8 *data, *end, *fw_end;
 	const struct firmware *fw;
-	int ret, i, offset = 0;
-	const u8 *data, *end;
+	size_t offset = 0;
+	int ret, i;
 	u8 offload_caps = 0;
 
 	ret = request_firmware(&fw, fw_wm, dev);
@@ -872,41 +873,72 @@ mt792x_get_offload_capability(struct device *dev, const char *fw_wm)
 		return ret;
 
 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
-		dev_err(dev, "Invalid firmware\n");
-		goto out;
+		goto invalid;
 	}
 
 	data = fw->data;
 	hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
+	if (hdr->n_region > (fw->size - sizeof(*hdr)) /
+			    sizeof(struct mt76_connac2_fw_region))
+		goto invalid;
+
+	fw_end = (const u8 *)hdr -
+		 hdr->n_region * sizeof(struct mt76_connac2_fw_region);
 
 	for (i = 0; i < hdr->n_region; i++) {
 		const struct mt76_connac2_fw_region *region;
+		u32 region_len;
 
 		region = (const void *)((const u8 *)hdr -
 					(hdr->n_region - i) * sizeof(*region));
-		offset += le32_to_cpu(region->len);
+		region_len = le32_to_cpu(region->len);
+		if (region_len > fw_end - fw->data - offset)
+			goto invalid;
+
+		offset += region_len;
 	}
 
+	if (fw_end - fw->data - offset < 16 + sizeof(*rel_info))
+		goto invalid;
+
 	data += offset + 16;
 	rel_info = (struct mt792x_realease_info *)data;
 	data += sizeof(*rel_info);
+	if (le16_to_cpu(rel_info->len) > fw_end - data)
+		goto invalid;
+
 	end = data + le16_to_cpu(rel_info->len);
 
 	while (data < end) {
+		u16 len;
+
+		if (end - data < sizeof(*rel_info))
+			goto invalid;
+
 		rel_info = (struct mt792x_realease_info *)data;
 		data += sizeof(*rel_info);
+		len = le16_to_cpu(rel_info->len);
+		if (len > end - data || rel_info->pad_len > end - data - len)
+			goto invalid;
 
 		if (rel_info->tag == MT792x_FW_TAG_FEATURE) {
 			struct mt792x_fw_features *features;
 
+			if (len < sizeof(*features))
+				goto invalid;
+
 			features = (struct mt792x_fw_features *)data;
 			offload_caps = features->data;
 			break;
 		}
 
-		data += le16_to_cpu(rel_info->len) + rel_info->pad_len;
+		data += len + rel_info->pad_len;
 	}
 
+	goto out;
+
+invalid:
+	dev_err(dev, "Invalid firmware\n");
 out:
 	release_firmware(fw);
 
-- 
2.34.1




More information about the Linux-mediatek mailing list