[PATCH] wifi: plfxlc: validate received USB transfer length before processing

From: Aamir Ahmed

Date: Sun Sep 06 2026 - 22:29:58 EST


rx_urb_complete() was computing the received data length from a
device-supplied field using le32_to_cpu(), but the protocol actually uses
big-endian byte order. More critically, this device-derived length was
passed to plfxlc_mac_rx() without any validation against the actual USB
transfer size (urb->actual_length), allowing a malicious or malfunctioning
device to cause out-of-bounds memory access.

Fix this by:

1. Using urb->actual_length in rx_urb_complete() instead of parsing a
length field from the device-supplied buffer with the wrong endianness.

2. Adding minimum length validation in plfxlc_mac_rx() before accessing
the rx_status header and payload_length field.

3. Validating payload_length against the actual received length to prevent
buffer over-reads.

4. Moving the plfxlc_filter_ack() call to after the buffer pointer has
been advanced past the rx_status header and length field, so it receives
a pointer to the actual 802.11 frame header instead of the rx_status
struct. The old code passed the raw buffer (pointing to struct
rx_status) cast to struct ieee80211_hdr, which is a type confusion bug.

Fixes: 68d57a07bfe5 ("wireless: add plfxlc driver for pureLiFi X, XL, XC devices")
Signed-off-by: Aamir Ahmed <elb12345@xxxxxxxxxxxxx>
---
drivers/net/wireless/purelifi/plfxlc/mac.c | 17 ++++++++++-------
drivers/net/wireless/purelifi/plfxlc/usb.c | 5 ++---
2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c
index a900421753ac..d2690cce796a 100644
--- a/drivers/net/wireless/purelifi/plfxlc/mac.c
+++ b/drivers/net/wireless/purelifi/plfxlc/mac.c
@@ -407,6 +407,9 @@ int plfxlc_mac_rx(struct ieee80211_hw *hw, const u8 *buffer,
if (!mac->vif)
return 0;

+ if (length < sizeof(struct rx_status) + sizeof(u32))
+ return -EINVAL;
+
status = (struct rx_status *)buffer;

memset(&stats, 0, sizeof(stats));
@@ -425,19 +428,19 @@ int plfxlc_mac_rx(struct ieee80211_hw *hw, const u8 *buffer,

mac->crc_errors = be64_to_cpu(status->crc_error_count);

- /* TODO bad frame check for CRC error*/
- if (plfxlc_filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) &&
- !mac->pass_ctrl)
- return 0;
-
buffer += sizeof(struct rx_status);
payload_length = get_unaligned_be32(buffer);
+ buffer += sizeof(u32);

- if (payload_length > 1560) {
+ if (payload_length > 1560 ||
+ payload_length + sizeof(struct rx_status) + sizeof(u32) > length) {
dev_err(plfxlc_mac_dev(mac), " > MTU %u\n", payload_length);
return 0;
}
- buffer += sizeof(u32);
+
+ if (plfxlc_filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) &&
+ !mac->pass_ctrl)
+ return 0;

fc = get_unaligned((__le16 *)buffer);
need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);
diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c
index 6d24086eb8b7..c33b9131bfdd 100644
--- a/drivers/net/wireless/purelifi/plfxlc/usb.c
+++ b/drivers/net/wireless/purelifi/plfxlc/usb.c
@@ -117,10 +117,9 @@ static void rx_urb_complete(struct urb *urb)
}

buffer = urb->transfer_buffer;
- length = le32_to_cpu(*(__le32 *)(buffer + sizeof(struct rx_status)))
- + sizeof(u32);
+ length = urb->actual_length;

- if (urb->actual_length != (PLF_MSG_STATUS_OFFSET + 1)) {
+ if (length != (PLF_MSG_STATUS_OFFSET + 1)) {
if (usb->initialized && usb->link_up)
handle_rx_packet(usb, buffer, length);
goto resubmit;
--
2.43.0