From nobody Mon Sep 28 23:12:41 2026 Received: from mail-lf1-f51.google.com (mail-lf1-f51.google.com [209.85.167.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 56D303A7F51 for ; Sat, 15 Aug 2026 10:33:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786790001; cv=none; b=K/FPwLd8kJq+LbKdM1aLRPqy7BZUj9qX37T1RHq2rWH+B2Eb0ZzYuTluVvUqPznXuPXn7GrZQokMSpSr+qtSqCflq/ymsImOyIyFsDgz5GqTsowdENcXiGDWSMxNzLOcLODN/c8QCqgiVoRHw7ZGxOQX1MdEweuYEaRNVDb3Hho= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786790001; c=relaxed/simple; bh=VzE7dHFcpp7Z1hppWUS73H1uQgBShBDQYBBo0XUsjCQ=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=AWY8yPD65QuTms9/mJVI3s9rj4sIvgvsaICzvWyZU7tT3Mh51jDqWJ1tOODT53NrRU0lg2Rg4FAj2eck5Jy/O7+U1qg1N1QRSaYH3jfiSPryeMan4dU4+YZYeYOz3WGC2D688rC/oZ6LrCRc/O4/zY0ViIr1yNT5IcLZXegFiMQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CjhB1Rph; arc=none smtp.client-ip=209.85.167.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CjhB1Rph" Received: by mail-lf1-f51.google.com with SMTP id 2adb3069b0e04-5b0148201fbso1631017e87.3 for ; Sat, 15 Aug 2026 03:33:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786789997; x=1787394797; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=nnQwhiS1oK35ru3NmuwF6q+bn/KVmSxsNWaO1by97NI=; b=CjhB1RphM9ezo0NcPkvhuQBWNVzIVWuNWfPfNP3GjToHqK2RDZZ7PbaPw4D1M2rAy4 mE0aBTmq9Xc6DLH2A70v8vdqtqB+Hr17KAeQqn3GFQJZ7w/do5j4rQd1WwNIWnMOIAtE k7zWya5wbp9OIJ80bX6Fu6jkvTbwm/ni0038E8llneHXzGl93FxTaobD28ubyzzSPfj1 qzKe4ujO8367sFwT5m/b3LjX+LyXkwfQqQpC01uYWeTeQBegv9BTm8Of5zomTEqKKA6u q5QSIVTqo5miyZUc81NSOUm3VwIEj6lZ2ZhCu8T4w/FXxZiGih9m+pDIf9zfQ3uhwWv9 3dEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786789997; x=1787394797; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=nnQwhiS1oK35ru3NmuwF6q+bn/KVmSxsNWaO1by97NI=; b=c/lK2e5RUC7d7FDu8Sg0HKumxib62ALTfzHdSRfYRAkpHgYWxGnhLDxf4UYpyp1yca r85KZ1ffREnpldCR3jLorTHzBWhnuSpbxrtPNPoqX8LCv8Ez1EUIEH7FKMzmmSexiPL5 BbVhvA+r0Sw50NxErGhYEcAwGBkTHnVZMlmO82BA1G2VCQVMbEbfndlnx2NaS2hYgphp xmk79xVMlEih18Y2mmyFnmQSY4e/vQfj1XkPmw9Ij572P95EQBGsuBgKcnAv1+AwKZC2 31K1+S2A2d+WXk8ith0yTOdPd4m/3ZzGiSXnWXP8XcF5Yosz7ZtI0LgR3YX1i8huY/NW lPMw== X-Forwarded-Encrypted: i=1; AHgh+RoV1zL48USskH+05wP9wgCkqm8nlC2PuEAM1dBw77+f/VGJjKgB8x0EekiowhCRE0XFvtB+snMALSDfEyc=@vger.kernel.org X-Gm-Message-State: AOJu0YzYRZZTGQFEHi43TkYtk4VjpBiDXJfkWUhgGBWMqDEcEIVyPNMZ +NLenHrtLHapu2QkN5jW3lXuwdDhAVEjCYoMJA3ATN7WI3g1wAQaZoeZ X-Gm-Gg: AR+sD10/Dt1RGU0Ww4BVzhMixvUh2HlKeSIFLxUVY2CrAQHlcviL/MiMKdihsac/Vah MvTHudVjWLBZQO8bYnsrjl8sNCsla1YzMWXx5CBLSN6hBjX0svSl5/NsxfX3DxnAA/c4SxonUbA 5Rph0wYCrSIc1+edFPAlghnrbMobGoXcm6CLM4qULOVkLXUtlccfa7VudM2pqQ16NO9q301zuX7 Ble3SOY3RYy1RK0ATqY7XONlfYlsktFyZZKFXU03CKqaTJZxeEmQtA31oaQhhI4Hcwzk+UHZG22 ojOcsHVSlHNol/tTaA4p3WbWRTBMbPx3thH4FdNo05fxpn2gLQF6braUrEJE/64FHQUHLbfbWK9 D0fKqNzD8ikmz04cYHljv1K3R6pQXMgdyexB0cL54OKN5UY9sR6N0S8s59MMs5YrgiN3UosQnUv DZFvu9ZFyzCL9niogQeE77blH89S51zuZJ7/6aQ0xNQ+ldwiav/SuwPQYXC3p+xhjMTg5nnfDLB eXeGi0voSvEkSOTom65+ZzqKpsv7Eu4aI4tjrGGLDO/rBtpLZHV8kaRkYM/ X-Received: by 2002:a05:6512:32c5:b0:5b3:cd0:6be6 with SMTP id 2adb3069b0e04-5b45914b25cmr2126112e87.54.1786789997153; Sat, 15 Aug 2026 03:33:17 -0700 (PDT) Received: from localhost ([188.234.148.119]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5b458b9a964sm1109010e87.1.2026.08.15.03.33.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Aug 2026 03:33:15 -0700 (PDT) From: Mikhail Gavrilov To: Felix Fietkau , Lorenzo Bianconi , Ryder Lee , Shayne Chen , Sean Wang Cc: Ming Yen Hsieh , Deren Wu , JB Tsai , linux-wireless@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Mikhail Gavrilov Subject: [PATCH wireless] wifi: mt76: mt7921: fix array-index-out-of-bounds in mt7921_load_clc() Date: Sat, 15 Aug 2026 15:33:12 +0500 Message-ID: <20260815103312.34080-1-mikhail.v.gavrilov@gmail.com> X-Mailer: git-send-email 2.55.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" mt7921_load_clc() walks the CLC region of the firmware image and uses clc->idx, a value taken straight from the blob, as an index into phy->clc[] without validating it. The array has MT792x_CLC_MAX_NUM (3) entries, so a firmware image carrying a section with a larger index overruns it. linux-firmware 20260810 does exactly that. Dumping the CLC region of mediatek/WIFI_RAM_CODE_MT7922_1.bin before and after the update: 20260622, region len 366448: idx=3D0 ver=3D1 nr_country=3D255 type=3D0 len=3D179384 idx=3D0 ver=3D1 nr_country=3D255 type=3D1 len=3D187064 20260810, region len 475488: idx=3D0 ver=3D1 nr_country=3D255 type=3D0 len=3D179384 idx=3D0 ver=3D1 nr_country=3D255 type=3D1 len=3D187054 idx=3D3 ver=3D1 nr_country=3D0 type=3D0 len=3D54520 idx=3D3 ver=3D1 nr_country=3D0 type=3D1 len=3D54530 and UBSAN reports the overrun on every probe: UBSAN: array-index-out-of-bounds in drivers/net/wireless/mediatek/mt76/mt7921/mcu.c:471:15 index 3 is out of range for type 'void *[3]' CPU: 19 UID: 0 PID: 261 Comm: kworker/19:1 Tainted: G U = 7.2.0-rc7-2f1baf1fc892-with-fixes-v1+ #125 PREEMPT(lazy) Hardware name: ASUS System Product Name/ROG STRIX B650E-I GAMING WIFI, BI= OS 3854 04/03/2026 Workqueue: events mt7921_init_work [mt7921_common] Call Trace: dump_stack_lvl+0x84/0xd0 ubsan_epilogue+0x5/0x2b __ubsan_handle_out_of_bounds.cold+0x4e/0x58 mt7921_load_clc+0x826/0xb80 [mt7921_common] mt7921_run_firmware+0x113/0x180 [mt7921_common] mt7921e_mcu_init+0xba/0x18d [mt7921e] mt7921_init_work+0xdb/0x3f0 [mt7921_common] process_one_work+0x901/0x1640 worker_thread+0x601/0xff0 kthread+0x36e/0x470 ret_from_fork+0x5bf/0x910 ret_from_fork_asm+0x1a/0x30 Both idx=3D3 sections are read out of bounds; UBSAN deduplicates by source location, so only one report appears. Booting the same kernel with linux-firmware 20260622 is clean, so the overrun is only reachable with the newer blob, but the missing check itself predates it. phy->clc[3] aliases phy->chip_cap, the u64 that follows the array in struct mt792x_phy. The report above is the read in the "do not init buf again" test. mt7921_mcu_get_nic_capability() runs before mt7921_load_clc() and fills chip_cap in from MT_NIC_CAP_CHIP_CAP, so on this device it is non-zero, the loop takes the continue path and no store happens. On a device whose firmware does not report that tag chip_cap stays zero, and the following devm_kmemdup() stores a heap pointer into it instead, enabling whatever MT792x_CHIP_CAP_* bits that pointer happens to have set. Skip CLC sections whose index the driver does not know about, so that they are ignored deliberately rather than by accident. With the firmware above this is not a functional change: the idx=3D3 sections are dropped either way. Use continue rather than break so that known sections following an unknown one are still parsed. mt7925_load_clc() has had an equivalent check since commit 9679ca7326e5 ("wifi: mt76: mt7925: fix a potential array-index-out-of-bounds issue for clc"). Fixes: 23bdc5d8cadf ("wifi: mt76: mt7921: introduce Country Location Contro= l support") Cc: stable@vger.kernel.org Signed-off-by: Mikhail Gavrilov --- ARRAY_SIZE(phy->clc) is used rather than a named constant on purpose. mt7921.h still carries enum { MT7921_CLC_POWER, MT7921_CLC_CHAN, MT7921_CLC_MAX_NUM, }; whose MT7921_CLC_MAX_NUM is 2 and does not match the array, which is sized by MT792x_CLC_MAX_NUM (3) in mt792x.h. That enum is otherwise unused except for MT7921_CLC_POWER, which happens to have the same value as MT792x_CLC_POWER. Removing it is a separate cleanup. The two idx=3D3 sections add roughly 109 KB of payload that the driver now discards explicitly. If mt7921 is supposed to consume them, that needs a MediaTek patch adding a fourth MT792x_CLC_* entry; this one only stops the out-of-bounds access. Tested on an MT7922 (mt7921e) on v7.2-rc7 with linux-firmware 20260810: the UBSAN report is gone and the regulatory domain is unchanged. drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/= wireless/mediatek/mt76/mt7921/mcu.c index 25b9437250f7..1b147b492b9f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -467,6 +467,9 @@ static int mt7921_load_clc(struct mt792x_dev *dev, cons= t char *fw_name) for (offset =3D 0; offset < len; offset +=3D le32_to_cpu(clc->len)) { clc =3D (const struct mt7921_clc *)(clc_base + offset); =20 + if (clc->idx >=3D ARRAY_SIZE(phy->clc)) + continue; + /* do not init buf again if chip reset triggered */ if (phy->clc[clc->idx]) continue; --=20 2.55.0