* [PATCH] wifi: mt76: mt7921: validate CLC firmware records
@ 2026-07-10 18:54 Laxman Acharya Padhya
2026-08-16 13:23 ` Mikhail Gavrilov
2026-08-16 17:48 ` [PATCH] wifi: mt76: mt7921: skip unknown " Laxman Acharya Padhya
0 siblings, 2 replies; 4+ messages in thread
From: Laxman Acharya Padhya @ 2026-07-10 18:54 UTC (permalink / raw)
To: Felix Fietkau
Cc: Lorenzo Bianconi, Ryder Lee, Shayne Chen, Sean Wang,
linux-wireless, linux-mediatek, linux-kernel
The CLC region is supplied by firmware, but the loader trusts the
region count and each record length. A malformed image can make the
region table pointer precede the firmware buffer, make the record loop
fail to advance, or index phy->clc past its end. Validate the table and
record bounds before dereferencing or copying.
Fixes: 23bdc5d8cadf ("wifi: mt76: mt7921: introduce Country Location
Control support")
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
---
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 28 +++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 25b9437250f7..564dd836e0b3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -415,7 +415,8 @@ static int mt7921_load_clc(struct mt792x_dev *dev,
const char *fw_name)
struct mt76_dev *mdev = &dev->mt76;
struct mt792x_phy *phy = &dev->phy;
const struct firmware *fw;
- int ret, i, len, offset = 0;
+ size_t clc_len, fw_data_len, len, offset = 0;
+ int ret, i;
u8 *clc_base = NULL, hw_encap = 0;
dev->phy.clc_chan_conf = 0xff;
@@ -441,13 +442,21 @@ static int mt7921_load_clc(struct mt792x_dev
*dev, const char *fw_name)
}
hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
+ if (hdr->n_region > (fw->size - sizeof(*hdr)) / sizeof(*region)) {
+ dev_err(mdev->dev, "Invalid firmware region table\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ fw_data_len = fw->size - sizeof(*hdr) -
+ hdr->n_region * sizeof(*region);
+
for (i = 0; i < hdr->n_region; i++) {
region = (const void *)((const u8 *)hdr -
(hdr->n_region - i) * sizeof(*region));
len = le32_to_cpu(region->len);
/* check if we have valid buffer size */
- if (offset + len > fw->size) {
+ if (len > fw_data_len - offset) {
dev_err(mdev->dev, "Invalid firmware region\n");
ret = -EINVAL;
goto out;
@@ -464,8 +473,19 @@ static int mt7921_load_clc(struct mt792x_dev
*dev, const char *fw_name)
if (!clc_base)
goto out;
- for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) {
+ for (offset = 0; offset < len; offset += clc_len) {
+ if (len - offset < sizeof(*clc)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
clc = (const struct mt7921_clc *)(clc_base + offset);
+ clc_len = le32_to_cpu(clc->len);
+ if (clc_len < sizeof(*clc) || clc_len > len - offset ||
+ clc->idx >= ARRAY_SIZE(phy->clc)) {
+ ret = -EINVAL;
+ goto out;
+ }
/* do not init buf again if chip reset triggered */
if (phy->clc[clc->idx])
@@ -477,7 +497,7 @@ static int mt7921_load_clc(struct mt792x_dev *dev,
const char *fw_name)
continue;
phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc,
- le32_to_cpu(clc->len),
+ clc_len,
GFP_KERNEL);
if (!phy->clc[clc->idx]) {
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] wifi: mt76: mt7921: validate CLC firmware records
2026-07-10 18:54 [PATCH] wifi: mt76: mt7921: validate CLC firmware records Laxman Acharya Padhya
@ 2026-08-16 13:23 ` Mikhail Gavrilov
2026-08-16 17:48 ` [PATCH] wifi: mt76: mt7921: skip unknown " Laxman Acharya Padhya
1 sibling, 0 replies; 4+ messages in thread
From: Mikhail Gavrilov @ 2026-08-16 13:23 UTC (permalink / raw)
To: Laxman Acharya Padhya, Felix Fietkau
Cc: Lorenzo Bianconi, Ryder Lee, Shayne Chen, Sean Wang,
Ming Yen Hsieh, Deren Wu, linux-wireless, linux-mediatek,
linux-kernel
This patch is in linux-next as 9417c5818a01, and on current shipping
firmware it stops mt7921e from probing at all.
An unknown clc->idx is treated as fatal:
if (clc_len < sizeof(*clc) || clc_len > len - offset ||
clc->idx >= ARRAY_SIZE(phy->clc)) {
ret = -EINVAL;
goto out;
}
but linux-firmware 20260810 ships an MT7922 image that legitimately
carries records with idx 3. Dumping the CLC region of
WIFI_RAM_CODE_MT7922_1.bin before and after that firmware update:
20260622, region len 366448:
idx=0 ver=1 nr_country=255 type=0 len=179384
idx=0 ver=1 nr_country=255 type=1 len=187064
20260810, region len 475488:
idx=0 ver=1 nr_country=255 type=0 len=179384
idx=0 ver=1 nr_country=255 type=1 len=187054
idx=3 ver=1 nr_country=0 type=0 len=54520
idx=3 ver=1 nr_country=0 type=1 len=54530
So mt7921_load_clc() returns -EINVAL, mt7921_run_firmware() fails, and
the probe retries the firmware ten times before giving up:
mt7921e 0000:0b:00.0: ASIC revision: 79220010
mt7921e 0000:0b:00.0: HW/SW Version: 0x8a108a10, Build Time: 20260724143257a
mt7921e 0000:0b:00.0: WM Firmware Version: ____000000, Build Time: 20260724143402
[ ... nine more identical pairs ... ]
mt7921e 0000:0b:00.0: hardware init failed
No interface is created. There is no dev_err on this path, so the only
clue is the retry loop. Loading mt7921_common with disable_clc=1, which
makes mt7921_load_clc() return before any of this, brings the device up
normally and the firmware is loaded once rather than ten times.
The rest of the patch is a real improvement - bounds-checking the region
table and each record length also closes an infinite loop on a
zero-length record. Only the handling of an unknown index needs to
change: an index the driver does not know about is not a malformed
image, it is a newer firmware, and the record should be skipped:
if (clc_len < sizeof(*clc) || clc_len > len - offset) {
ret = -EINVAL;
goto out;
}
if (clc->idx >= ARRAY_SIZE(phy->clc))
continue;
I sent an overlapping patch yesterday, "wifi: mt76: mt7921: fix
array-index-out-of-bounds in mt7921_load_clc()", before I found this one
in linux-next; I will mark mine superseded, since this patch is the
broader fix. Happy to send the one-line change above as a follow-up
patch and test it here, or leave it to you to fold in before this
reaches mainline.
Separately, it would be useful to know what CLC index 3 actually
contains - roughly 109 KB of payload in two hw_encap variants that the
driver currently discards either way.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] wifi: mt76: mt7921: skip unknown CLC firmware records
2026-07-10 18:54 [PATCH] wifi: mt76: mt7921: validate CLC firmware records Laxman Acharya Padhya
2026-08-16 13:23 ` Mikhail Gavrilov
@ 2026-08-16 17:48 ` Laxman Acharya Padhya
2026-08-17 20:16 ` Mikhail Gavrilov
1 sibling, 1 reply; 4+ messages in thread
From: Laxman Acharya Padhya @ 2026-08-16 17:48 UTC (permalink / raw)
To: Felix Fietkau
Cc: Lorenzo Bianconi, Ryder Lee, Shayne Chen, Sean Wang, Deren Wu,
Ming Yen Hsieh, Mikhail Gavrilov, linux-wireless, linux-mediatek,
linux-kernel
Treat an out-of-range CLC index as newer firmware rather than a
malformed image. linux-firmware 20260810 ships MT7922 records with
idx 3, and rejecting them made mt7921e fail to probe.
Keep the record-length checks, and report those as errors so a
truncated table is visible instead of a silent retry loop.
Fixes: 9417c5818a01 ("wifi: mt76: mt7921: validate CLC firmware records")
Reported-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
---
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index a118a301564c..40546005c743 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -477,18 +477,23 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
for (offset = 0; offset < len; offset += clc_len) {
if (len - offset < sizeof(*clc)) {
+ dev_err(mdev->dev, "Invalid CLC record\n");
ret = -EINVAL;
goto out;
}
clc = (const struct mt7921_clc *)(clc_base + offset);
clc_len = le32_to_cpu(clc->len);
- if (clc_len < sizeof(*clc) || clc_len > len - offset ||
- clc->idx >= ARRAY_SIZE(phy->clc)) {
+ if (clc_len < sizeof(*clc) || clc_len > len - offset) {
+ dev_err(mdev->dev, "Invalid CLC record\n");
ret = -EINVAL;
goto out;
}
+ /* Newer firmware may add records this driver does not use yet */
+ if (clc->idx >= ARRAY_SIZE(phy->clc))
+ continue;
+
/* do not init buf again if chip reset triggered */
if (phy->clc[clc->idx])
continue;
--
2.51.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] wifi: mt76: mt7921: skip unknown CLC firmware records
2026-08-16 17:48 ` [PATCH] wifi: mt76: mt7921: skip unknown " Laxman Acharya Padhya
@ 2026-08-17 20:16 ` Mikhail Gavrilov
0 siblings, 0 replies; 4+ messages in thread
From: Mikhail Gavrilov @ 2026-08-17 20:16 UTC (permalink / raw)
To: Laxman Acharya Padhya, Felix Fietkau
Cc: Lorenzo Bianconi, Ryder Lee, Shayne Chen, Sean Wang,
Ming Yen Hsieh, Deren Wu, linux-wireless, linux-mediatek,
linux-kernel, Mikhail Gavrilov
Thanks for the quick turnaround.
Tested on an MT7922 (mt7921e) with linux-firmware 20260810 - the image
whose CLC region carries the idx 3 records - on a lockdep and UBSAN
build of mainline at fd923b32d761, with 9417c5818a01 applied underneath.
The device probes normally: the RAM firmware is loaded once rather than
ten times, wlp11s0 appears, association with a 6 GHz AP works (channel
37, 6135 MHz, 160 MHz), and switching between a 5 GHz and a 6 GHz BSS
and back is clean. No "hardware init failed", no "Invalid CLC record",
and no UBSAN report - so the bounds checks are still doing their job on
the very firmware that used to trip them.
Tested-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
One nit, take it or leave it: both length failures print the same
"Invalid CLC record", so the log does not distinguish a table that ends
mid-header from a record whose length is out of range. Two distinct
strings would make a future report easier to read.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-17 20:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 18:54 [PATCH] wifi: mt76: mt7921: validate CLC firmware records Laxman Acharya Padhya
2026-08-16 13:23 ` Mikhail Gavrilov
2026-08-16 17:48 ` [PATCH] wifi: mt76: mt7921: skip unknown " Laxman Acharya Padhya
2026-08-17 20:16 ` Mikhail Gavrilov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox