[PATCH] wifi: wilc1000: validate packet bounds in RX buffer parsing

From: Aamir Ahmed

Date: Sun Sep 06 2026 - 19:40:04 EST


wilc_wlan_handle_rx_buff() parses a firmware DMA receive buffer
containing multiple packets. The header, packet length, packet
offset, and total-length fields are all read from firmware-provided
data without validating them against the remaining buffer size.

A malformed or corrupted receive buffer can cause out-of-bounds reads
in three ways:

1. The 4-byte packet header is read with get_unaligned_le32() when
fewer than 4 bytes remain in the buffer.

2. For management frames, HOST_HDR_OFFSET + pkt_len bytes are accessed
past the current offset without checking they fit within tp_len.

3. For data and config frames, pkt_offset + pkt_len bytes are accessed
without similar bounds checks.

The do-while loop condition (offset < size) is insufficient because it
does not guarantee that a full header or packet body fits in the
remaining bytes.

Fix by:
- Converting the do-while to a while loop that ensures at least
sizeof(u32) bytes remain before reading the header.
- Checking tp_len against the remaining buffer size.
- Validating pkt_len against tp_len for management frames
(accounting for HOST_HDR_OFFSET).
- Validating pkt_offset and pkt_len against tp_len for data
and config frames.

Fixes: c5c77ba18ea6 ("staging: wilc1000: Add SDIO/SPI 802.11 driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Aamir Ahmed <elb12345@xxxxxxxxxxxxx>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 4b116fe6f9ea..3ebcd688f2dd 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -1111,7 +1111,7 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
int is_cfg_packet;
u8 *buff_ptr;

- do {
+ while (offset + sizeof(u32) <= size) {
buff_ptr = buffer + offset;
header = get_unaligned_le32(buff_ptr);

@@ -1123,11 +1123,19 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
if (pkt_len == 0 || tp_len == 0)
break;

+ if (tp_len > size - offset)
+ break;
+
if (pkt_offset & IS_MANAGMEMENT) {
+ if (tp_len < HOST_HDR_OFFSET || pkt_len > tp_len - HOST_HDR_OFFSET)
+ break;
buff_ptr += HOST_HDR_OFFSET;
wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len,
pkt_offset & IS_MGMT_AUTH_PKT);
} else {
+ if (pkt_offset > tp_len ||
+ pkt_len > tp_len - pkt_offset)
+ break;
if (!is_cfg_packet) {
wilc_frmw_to_host(wilc, buff_ptr, pkt_len,
pkt_offset);
@@ -1148,7 +1156,7 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
}
}
offset += tp_len;
- } while (offset < size);
+ }
}

static void wilc_wlan_handle_rxq(struct wilc *wilc)
--
2.43.0