[PATCH] wifi: libertas: cancel fw_timeout on disconnect
YuanZhe Liu
25031212351 at stu.xidian.edu.cn
Sat Oct 17 00:45:49 PDT 2026
if_usb_disconnect() frees the if_usb_card structure without ever cancelling
its fw_timeout timer, which can still be pending in the timer wheel at that
point.
That timer is armed by the RX completion handler if_usb_receive_fwload()
with a five second deadline while a firmware download is in progress. The
only place that cancels it is the asynchronous firmware download callback
if_usb_prog_firmware(), and it does so before killing the RX URBs:
wait_event_interruptible(cardp->fw_wq,
cardp->surprise_removed ||
cardp->fwdnldover);
timer_delete_sync(&cardp->fw_timeout);
usb_kill_anchored_urbs(&cardp->rx_submitted);
Killing the URBs does not undo a timer that a completion handler which was
already running re-armed in between, so fw_timeout can still be pending
when the callback returns.
If the device is disconnected at that point, for example after a
USBDEVFS_RESET forced unbind or a physical unplug during firmware download,
the card structure is freed with its timer still queued in a timer wheel
bucket:
BUG: KASAN: slab-use-after-free in enqueue_timer+0x236/0x250
Write of size 8 at addr ffff88800ed324c8
Allocated by task 1623:
if_usb_probe+0xc8/0xc60
drivers/net/wireless/marvell/libertas/if_usb.c:205
Freed by task 1686:
if_usb_disconnect+0x1c6/0x270
drivers/net/wireless/marvell/libertas/if_usb.c:322
The buggy address is located 200 bytes inside of
freed 512-byte region [ffff88800ed32400, ffff88800ed32600)
The offset corresponds to fw_timeout.entry.pprev, so the timer core later
rewrites the list node of a timer living in freed memory, both when
enqueuing another timer into the same bucket and when moving the bucket to
the expired list in run_timer_softirq().
Cancel the timer in if_usb_disconnect(), after if_usb_free() has killed the
RX URBs, which stops the completion path from arming it again, and before
the card is freed.
Fixes: 4f82f5c853e3 ("libertas: switch to a waitqueue and timer for handling USB firmware load")
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/if_usb.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index 5cc0c5cac257..3410d6850db2 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -319,6 +319,12 @@ static void if_usb_disconnect(struct usb_interface *intf)
/* Unlink and free urb */
if_usb_free(cardp);
+
+ /* A firmware download in progress can re-arm fw_timeout from the RX
+ * completion path, so make sure it is gone before freeing the card.
+ */
+ timer_delete_sync(&cardp->fw_timeout);
+
kfree(cardp);
usb_set_intfdata(intf, NULL);
--
2.34.1
More information about the libertas-dev
mailing list