Skip to content

Commit 03fb92a

Browse files
brookebasileKalle Valo
authored andcommitted
ath9k: hif_usb: fix race condition between usb_get_urb() and usb_kill_anchored_urbs()
Calls to usb_kill_anchored_urbs() after usb_kill_urb() on multiprocessor systems create a race condition in which usb_kill_anchored_urbs() deallocates the URB before the completer callback is called in usb_kill_urb(), resulting in a use-after-free. To fix this, add proper lock protection to usb_kill_urb() calls that can possibly run concurrently with usb_kill_anchored_urbs(). Reported-by: [email protected] Link: https://syzkaller.appspot.com/bug?id=cabffad18eb74197f84871802fd2c5117b61febf Signed-off-by: Brooke Basile <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5a6bd84 commit 03fb92a

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

drivers/net/wireless/ath/ath9k/hif_usb.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,19 @@ static void hif_usb_stop(void *hif_handle)
449449
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
450450

451451
/* The pending URBs have to be canceled. */
452+
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
452453
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
453454
&hif_dev->tx.tx_pending, list) {
455+
usb_get_urb(tx_buf->urb);
456+
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
454457
usb_kill_urb(tx_buf->urb);
458+
list_del(&tx_buf->list);
459+
usb_free_urb(tx_buf->urb);
460+
kfree(tx_buf->buf);
461+
kfree(tx_buf);
462+
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
455463
}
464+
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
456465

457466
usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
458467
}
@@ -762,27 +771,37 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
762771
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
763772
unsigned long flags;
764773

774+
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
765775
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
766776
&hif_dev->tx.tx_buf, list) {
777+
usb_get_urb(tx_buf->urb);
778+
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
767779
usb_kill_urb(tx_buf->urb);
768780
list_del(&tx_buf->list);
769781
usb_free_urb(tx_buf->urb);
770782
kfree(tx_buf->buf);
771783
kfree(tx_buf);
784+
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
772785
}
786+
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
773787

774788
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
775789
hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
776790
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
777791

792+
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
778793
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
779794
&hif_dev->tx.tx_pending, list) {
795+
usb_get_urb(tx_buf->urb);
796+
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
780797
usb_kill_urb(tx_buf->urb);
781798
list_del(&tx_buf->list);
782799
usb_free_urb(tx_buf->urb);
783800
kfree(tx_buf->buf);
784801
kfree(tx_buf);
802+
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
785803
}
804+
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
786805

787806
usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
788807
}

0 commit comments

Comments
 (0)