lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 18 Aug 2023 19:06:58 -0400
From:   Alan Stern <stern@...land.harvard.edu>
To:     Thinh Nguyen <Thinh.Nguyen@...opsys.com>
Cc:     Andrey Konovalov <andreyknvl@...il.com>,
        Felipe Balbi <balbi@...nel.org>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        USB list <linux-usb@...r.kernel.org>,
        LKML <linux-kernel@...r.kernel.org>
Subject: Re: dwc3: unusual handling of setup requests with wLength == 0

On Fri, Aug 18, 2023 at 07:49:27PM +0000, Thinh Nguyen wrote:
> On Thu, Aug 17, 2023, Alan Stern wrote:
> > On Fri, Aug 18, 2023 at 03:10:48AM +0000, Thinh Nguyen wrote:
> > > I was referring to the next request. It should not be processed until
> > > the first request is completed. Depending on the type of request, if
> > > there's a delayed_status, the dwc3 driver will not prepare for the
> > > Status stage and Setup stage (after status completion) to proceed to the
> > > _next_ ->setup callback.
> > > 
> > > My understanding from the described problem is that somehow dwc3
> > > processes the next request immediately without waiting for the raw
> > > gadget preparing the data stage.
> > 
> > Um.  This is one of the design flaws I mentioned: a new SETUP packet 
> > arriving before the old control transfer is finished.  The USB spec 
> > requires devices to accept the new SETUP packet and abort the old 
> > transfer.  So in this case, processing the next request immediately is 
> > the right thing to do.
> 
> No, as I've mentioned, from the gadget driver, it should not see the
> next ->setup until the first control transfer completion, regardless
> whether the transfer completed with error code due to abort or not.
> Everything should happen sequentially from the gadget driver. This
> should be handled in the dwc3 driver (though we missed a setup_pending
> status check in the data phase that needs to be fixed now that I look at
> it again).

Actually I agree with you.  When a new SETUP packet arrives before the 
old control transfer has finished, the UDC driver should cancel all 
pending requests and then invoke the ->setup() callback.  (I don't think 
there is a standard error code for the cancelled requests; net2280 seems 
to use -EPROTO whereas dummy-hcd seems to use -EOVERFLOW.)

> Perhaps the core design should be so that this synchronization does not
> depend on the udc driver implementation.

Do you mean the UDC core?  I don't see how it could get involved in 
managing control transfers.

> > One question is why Andrey is observing a new ->setup() callback 
> > happening so soon?  The host is supposed to allow a fairly long time for 
> > standard control requests to complete.  If the userspace component of 
> > the Raw Gadget takes too long to act, the transfer could time out and be 
> > cancelled on the host.  But "too long" means several seconds -- is that 
> > really what's going on here?
> 
> As I noted initially, it should not happen so I'm not sure what's really
> the problem here. Granted that the setup_pending check for data phase is
> missing in dwc3 driver, there should not be a problem unless the host
> actually aborted a control transfer. Also, there should be no data phase
> for wlength=0 even for IN direction if we go through the composite
> layer. So, I doubt that's what happening here.
> 
> Perhaps Andrey can clarify.

My impression from his initial email was that something different was 
happening.  It sounded like his ->setup() callback was invoked with 
wLength = 0, but before the Raw Gadget driver was ready to queue a 
response request, the UDC driver sent an automatic status, at which 
point the host sent another SETUP packet.  So the gadget driver got two 
->setup() callbacks in a row with no chance to do anything in between.

> > > I was talking in context of 0-length transfer (albeit I forgot about the
> > > special case of control OUT doesn't have 3-stage).
> > > 
> > > If it's a vendor request 0-length transfer, without responding with
> > > USB_GADGET_DELAYED_STATUS, the dwc3 will proceed with preparing the
> > > status stage.
> > 
> > This may be a holdover from the early days of the Gadget subsystem.  My 
> > memory from back then isn't very good; I vaguely recall that the first 
> > UDC drivers would queue their automatic Status-stage requests if wLength 
> > was 0 and ->setup() returned 0 (which would explain why 
> > USB_GADGET_DELAYED_STATUS had to be invented).  Unless I'm completely 
> > confused, that's not how UDC drivers are supposed to act now.

I did a little checking.  The USB_GADGET_DELAYED_STATUS mechanism was 
introduced for use by the composite framework -- not in order to make a 
UDC driver work properly.

> For dwc3, it's been like this since the beginning that it automatically
> queues the status upon host request. USB_GADGET_DELAYED_STATUS was
> introduced to support scenarios where the device may need a longer time
> to process the specific request (such as SET_CONFIGURATION).

It's hard to be sure, but that may be the cause of Andrey's problem.  He 
mentioned something about the Raw Gadget's ->setup() routine returning 
USB_GADGET_DELAYED_STATUS when the problem occurred, but I think he 
meant that it did this for the second callback, not the first one.

Still, I recommand that dwc3 not automatically queue a Status request 
when wLength is 0.  Gadget drivers don't expect UDC drivers to handle 
this for them.  For example, look at the composite_setup() function in 
composite.c.  It does this:

	/* respond with data transfer before status phase? */
	if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
		req->length = value;
		req->context = cdev;
		req->zero = value < w_length;
		value = composite_ep0_queue(cdev, req, GFP_ATOMIC);

Clearly it doesn't want the UDC driver to queue a request for it, no 
matter what wLength or value is set to.

Alan Stern

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ