Re: WARNING in usbhid_raw_request/usb_submit_urb (3)

From: Alan Stern
Date: Fri Apr 24 2020 - 15:14:18 EST


On Fri, 24 Apr 2020, syzbot wrote:

> Hello,
>
> syzbot has tested the proposed patch but the reproducer still triggered crash:
> INFO: task hung in usb_disable_device

That wasn't what I expected. Still, the important information was
present: The reset was instigated by hid_io_error(), because of some
sort of communication error.

Note that the hid_submit_out, hid_submit_ctrl, and so on don't test the
RESET_PENDING flag. At least, not with any proper synchronization.
That's why we got an URB submitted while the device was being reset.

Nevertheless, the USB core should be able to handle such things without
a big WARNing, particularly for ep0. The patch below tries to do this.

Alan Stern

#syz test: https://github.com/google/kasan.git 0fa84af8

Index: usb-devel/drivers/usb/core/urb.c
===================================================================
--- usb-devel.orig/drivers/usb/core/urb.c
+++ usb-devel/drivers/usb/core/urb.c
@@ -204,8 +204,17 @@ int usb_urb_ep_type_check(const struct u
const struct usb_host_endpoint *ep;

ep = usb_pipe_endpoint(urb->dev, urb->pipe);
- if (!ep)
- return -EINVAL;
+ if (!ep) {
+ /*
+ * Special case: The pointers for ep0 are temporarily cleared
+ * during device resets. We won't count this as an error;
+ * drivers can reasonably expect that ep0 always exists.
+ */
+ if (usb_pipeendpoint(urb->pipe) == 0)
+ ep = &urb->dev->ep0;
+ else
+ return -EINVAL;
+ }
if (usb_pipetype(urb->pipe) != pipetypes[usb_endpoint_type(&ep->desc)])
return -EINVAL;
return 0;