[PATCH] wifi: libertas_tf: fix NULL pointer dereference in if_usb_receive()

YuanZhe Liu 25031212351 at stu.xidian.edu.cn
Wed Oct 28 09:49:02 PDT 2026


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 at vger.kernel.org
Co-developed-by: Bin Yu <byu at xidian.edu.cn>
Signed-off-by: Bin Yu <byu at xidian.edu.cn>
Co-developed-by: Cheng Wen <wencheng at xidian.edu.cn>
Signed-off-by: Cheng Wen <wencheng at xidian.edu.cn>
Signed-off-by: YuanZhe Liu <25031212351 at stu.xidian.edu.cn>
---
 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




More information about the libertas-dev mailing list