Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f6095b0 authored by Anirudh Rayabharam's avatar Anirudh Rayabharam Committed by Greg Kroah-Hartman
Browse files

usbip: give back URBs for unsent unlink requests during cleanup

[ Upstream commit 258c81b341c8025d79073ce2d6ce19dcdc7d10d2 ]

In vhci_device_unlink_cleanup(), the URBs for unsent unlink requests are
not given back. This sometimes causes usb_kill_urb to wait indefinitely
for that urb to be given back. syzbot has reported a hung task issue [1]
for this.

To fix this, give back the urbs corresponding to unsent unlink requests
(unlink_tx list) similar to how urbs corresponding to unanswered unlink
requests (unlink_rx list) are given back.

[1]: https://syzkaller.appspot.com/bug?id=08f12df95ae7da69814e64eb5515d5a85ed06b76



Reported-by: default avatar <syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com>
Tested-by: default avatar <syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com>
Reviewed-by: default avatarShuah Khan <skhan@linuxfoundation.org>
Signed-off-by: default avatarAnirudh Rayabharam <mail@anirudhrb.com>
Link: https://lore.kernel.org/r/20210820190122.16379-2-mail@anirudhrb.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 9a4a6805
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -952,9 +952,33 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
	spin_lock(&vdev->priv_lock);

	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
		struct urb *urb;

		/* give back urb of unsent unlink request */
		pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);

		urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
		if (!urb) {
			list_del(&unlink->list);
			kfree(unlink);
			continue;
		}

		urb->status = -ENODEV;

		usb_hcd_unlink_urb_from_ep(hcd, urb);

		list_del(&unlink->list);

		spin_unlock(&vdev->priv_lock);
		spin_unlock_irqrestore(&vhci->lock, flags);

		usb_hcd_giveback_urb(hcd, urb, urb->status);

		spin_lock_irqsave(&vhci->lock, flags);
		spin_lock(&vdev->priv_lock);

		kfree(unlink);
	}

	while (!list_empty(&vdev->unlink_rx)) {