Re: Inconsistency in how URBs are unlinked

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

 



On Thu, 16 Jan 2020, Greg Kroah-Hartman wrote:

> On Thu, Jan 16, 2020 at 01:34:21PM -0800, Chris Dickens wrote:
> > Hi,
> > 
> > A bug [1] has been reported against libusb about a segfault that
> > occurs when a device is disconnected while processing isochronous
> > transfers.  In my investigation I discovered an interesting
> > inconsistency in how URBs are unlinked across the USB core.
> > 
> > The usbfs driver will unlink URBs in the same order they are
> > submitted.

You're talking about destroy_async(), right?  Yes, I should change that 
to make it go in backwards order -- thanks for pointing this out.

> >  From what I can see this code is executed when
> > setting/releasing an interface or when alloc'ing/freeing streams.  I
> > see there is also a call within the usbfs driver's disconnect
> > function, but that appears to be a no-op (is this really the case?) as
> > by the time that function is called the interface would have already
> > been disabled and thus usb_hcd_flush_endpoint() would have been
> > called.

Not necessarily.  You can unbind a driver such as usbfs without 
disabling the interface.

> > Since commit 2eac136243 ("usb: core: unlink urbs from the tail of the
> > endpoint's urb_list"), the usb_hcd_flush_endpoint() function will
> > unlink URBs in the reverse order of submission.  This subtle change is
> > what led to the crash within libusb.  The bug manifests when transfers
> > within libusb are split into multiple URBs.  Prior to this change, the
> > order in which URBs were reaped matched the order in which they were
> > submitted.  Internally libusb expects this order to match and frees
> > memory when it encounters the last URB in a multi-URB transfer, but
> > since it reaps the last URB first the memory is freed right away and
> > things take a turn when the freed memory is accessed when reaping the
> > other URB(s) in that same transfer.
> 
> That commit was from July 2017, has no one really noticed since then?
> 
> Anyway, who is splitting the urb up, libusb or usbfs?  I'm guessing
> libusb here as otherwise this wouldn't be an issue, but if you are
> splitting them up, shouldn't you never count on the order in which they
> are handled as some host controllers can reorder them (I think xhci
> can).  So this type of fix for libusb is to be expected I would think,
> you can't count on an async interface ever working in an ordered manner,
> right?

Host controllers can't reorder URBs for the same endpoint, although 
they can reorder URBs for differing endpoints.

> Also, what does other operating systems do here?

In general it is better to unlink URBs in reverse order.  This
eliminates all possibility that the kernel will unlink URB x before it
executes but then URB x+1 will get executed before the kernel can
unlink it.

> > I will fix libusb to account for this behavior, but I thought it worth
> > mentioning as this new behavior isn't what I (and possibly others)
> > necessarily expect.
> 
> New as of 2017 :)

The kernel guarantees that URBs for a single endpoint will complete in
order _unless_ they have been unlinked.  Unlinked URBs can complete in
any order -- and not necessarily the order in which they were unlinked.

Alan Stern




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux