[PATCH wireless] wifi: mwifiex: validate scan response TLV sizes before indexed access

From: Tristan Madani

Date: Sun Oct 25 2026 - 14:12:23 EST


The scan response handler indexes into TSF and channel-band TLV arrays
using a loop counter derived from the number of BSS entries, but never
checks whether the TLV data is large enough. A firmware response with
fewer TLV entries than BSS entries leads to reads past the TLV buffer.

Add bounds checks that verify each indexed access falls within the
TLV data length before dereferencing. Initialize chan_band to NULL and
fw_tsf to zero at the start of each iteration so that a short TLV does
not leave stale values from the previous BSS entry. Gate the
neighbor-discovery branch on chan_band being non-NULL to prevent
dereferencing an uninitialized pointer when the bounds check rejects
the current entry.

Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Tristan Madani <tristan@xxxxxxxxxxxxxxxxxxx>
---
drivers/net/wireless/marvell/mwifiex/scan.c | 23 ++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index bdd4b8465863b..4c4bbd4b3b73b 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -2208,6 +2208,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
}

for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
+ chan_band = NULL;
+ fw_tsf = 0;
/*
* If the TSF TLV was appended to the scan results, save this
* entry's TSF value in the fw_tsf field. It is the firmware's
@@ -2215,17 +2217,28 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
* received.
*/
if (tsf_tlv)
- memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
- sizeof(fw_tsf));
+ if ((idx + 1) * TSF_DATA_SIZE <=
+ le16_to_cpu(tsf_tlv->header.len))
+ memcpy(&fw_tsf,
+ &tsf_tlv->tsf_data[idx *
+ TSF_DATA_SIZE],
+ sizeof(fw_tsf));

if (chan_band_tlv) {
- chan_band = &chan_band_tlv->chan_band_param[idx];
- radio_type = &chan_band->radio_type;
+ if ((idx + 1) * sizeof(*chan_band) <=
+ le16_to_cpu(chan_band_tlv->header.len)) {
+ chan_band =
+ &chan_band_tlv->chan_band_param[idx];
+ radio_type = &chan_band->radio_type;
+ } else {
+ chan_band = NULL;
+ radio_type = NULL;
+ }
} else {
radio_type = NULL;
}

- if (chan_band_tlv && adapter->nd_info) {
+ if (chan_band && chan_band_tlv && adapter->nd_info) {
adapter->nd_info->matches[idx] =
kzalloc(sizeof(*pmatch) + sizeof(u32),
GFP_ATOMIC);
--
2.47.3