[PATCH] wifi: libertas_tf: fix NULL pointer dereference in if_usb_receive()
From: YuanZhe Liu
Date: Wed Oct 28 2026 - 12:53:56 EST
if_usb_receive() takes the receive skb from cardp->rx_skb and
immediately dereferences skb->data to get at the packet header:
__le32 *pkt = (__le32 *) skb->data;
That happens before the URB status or the skb itself is validated.
cardp->rx_skb can already be NULL when the callback runs, because
__if_usb_submit_rx_urb() frees the freshly allocated skb and clears
cardp->rx_skb when usb_submit_urb() fails:
kfree_skb(skb);
cardp->rx_skb = NULL;
The submission fails with -EBUSY while the previous rx_urb is still
queued on the endpoint, or with -ENODEV once the device is no longer
configured. usb_fill_bulk_urb() has already installed if_usb_receive()
as the completion handler of that still queued URB, so when
usb_kill_urb() from if_usb_free() later hands the URB back with
-ENOENT and a zero actual_length, the callback runs with skb == NULL
and faults on skb->data:
general protection fault, probably for non-canonical address
0xdffffc0000000019: 0000 [#1] SMP KASAN
KASAN: null-ptr-deref in range [0x00000000000000c8-0x00000000000000cf]
RIP: 0010:if_usb_receive+0xd6/0x3a0
...
Call Trace:
__usb_hcd_giveback_urb
usb_giveback_urb_bh
...
usb_kill_urb
if_usb_free
if_usb_probe
Compute pkt only in the branch that actually consumes the payload,
after the URB status and the skb have been validated, so a callback
without a valid skb leaves through the existing retry path. The
handling of a non-zero status with a non-empty payload is untouched,
which keeps the current recovery after transient errors.
Fixes: c305a19a0d0a47ac59a58865a4a63be65b1bf7c8 ("libertas_tf: usb specific functions")
Cc: stable@xxxxxxxxxxxxxxx
Co-developed-by: Bin Yu <byu@xxxxxxxxxxxxx>
Signed-off-by: Bin Yu <byu@xxxxxxxxxxxxx>
Co-developed-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: YuanZhe Liu <25031212351@xxxxxxxxxxxxxxxxx>
---
drivers/net/wireless/marvell/libertas_tf/if_usb.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index b85c6d783bf7..bca2912a1909 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -625,7 +625,7 @@ static void if_usb_receive(struct urb *urb)
int recvlength = urb->actual_length;
uint8_t *recvbuff = NULL;
uint32_t recvtype = 0;
- __le32 *pkt = (__le32 *) skb->data;
+ __le32 *pkt = NULL;
lbtf_deb_enter(LBTF_DEB_USB);
@@ -637,6 +637,12 @@ static void if_usb_receive(struct urb *urb)
goto setup_for_next;
}
+ if (!skb) {
+ lbtf_deb_usbd(&cardp->udev->dev, "RX URB without skb\n");
+ goto setup_for_next;
+ }
+
+ pkt = (__le32 *)skb->data;
recvbuff = skb->data;
recvtype = le32_to_cpu(pkt[0]);
lbtf_deb_usbd(&cardp->udev->dev,
--
2.34.1