[PATCH 11/11] wifi: mt76: mt792x: bound firmware release-info parsing
From: Jiale Yao
Date: Mon Oct 19 2026 - 22:48:28 EST
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@xxxxxxx>
---
.../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