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@vger.kernel.org Co-developed-by: Bin Yu Signed-off-by: Bin Yu Co-developed-by: Cheng Wen Signed-off-by: Cheng Wen Signed-off-by: YuanZhe Liu <25031212351@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