qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: USB pass-through problems


From: Gerd Hoffmann
Subject: Re: USB pass-through problems
Date: Thu, 28 May 2020 15:28:50 +0200

> > > #2  0x00007f23e8bfbb13 in libusb_handle_events_timeout_completed () at 
> > > /lib64/libusb-1.0.so.0
> > > #3  0x000055e09854b7da in usb_host_abort_xfers (s=0x55e09b036dd0) at 
> > > hw/usb/host-libusb.c:963

> > Hmm, does reverting 76d0a9362c6a6a7d88aa18c84c4186c9107ecaef change
> > behavior?
> 
> Yes it does. Reverting that patch fixes the problem, no hang and device
> reconnects without problem.

Hmm.  Looks like an libusb bug to me, it seems to not call the
completion callback for the canceled transfers (which it should do
according to the docs), so qemu waits for this to happen forever.

We can certainly add a limit here (see below), question is how to
handle the canceled but not completed transfers then.  I suspect
we have to leak them to make sure we don't get use-after-free
access from libusb ...

cheers,
  Gerd

diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index e28441379d99..4c3b5b140d9d 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -944,30 +944,45 @@ fail:
         libusb_close(s->dh);
         s->dh = NULL;
         s->dev = NULL;
     }
     return -1;
 }
 
 static void usb_host_abort_xfers(USBHostDevice *s)
 {
     USBHostRequest *r, *rtmp;
+    int limit = 100;
 
     QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) {
         usb_host_req_abort(r);
     }
 
     while (QTAILQ_FIRST(&s->requests) != NULL) {
         struct timeval tv;
         memset(&tv, 0, sizeof(tv));
         tv.tv_usec = 2500;
         libusb_handle_events_timeout(ctx, &tv);
+        if (--limit == 0) {
+            /*
+             * Don't wait forever for libusb calling the complete
+             * callback (which will unlink and free the request).
+             *
+             * Leaking memory here, to make sure libusb will not
+             * access memory which we have released already.
+             */
+            QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) {
+                fprintf(stderr, "%s: leaking usb request %p\n", __func__, r);
+                QTAILQ_REMOVE(&s->requests, r, next);
+            }
+            return;
+        }
     }
 }
 
 static int usb_host_close(USBHostDevice *s)
 {
     USBDevice *udev = USB_DEVICE(s);
 
     if (s->dh == NULL) {
         return -1;
     }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]