Re: [PATCH v2] usb: gadget: aspeed_udc: avoid past-the-end iterator in dequeue

Andrew Jeffery <[email protected]>
Newsgroups org.ozlabs.lists.linux-aspeed,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-usb
Message-ID <eeadb3378066f18cf36469adfc3a70be3ad7b787.camel@codeconstruct.com.au>
On Tue, 2026-05-19 at 16:02 +0800, Maoyi Xie wrote:
> ast_udc_ep_dequeue() declares the loop cursor `req` outside the
> list_for_each_entry(). After the loop it tests `&req->req != _req`
> to decide whether the request was found. If the queue holds no
> match, `req` is past-the-end. It then aliases
> container_of(&ep->queue, struct ast_udc_request, queue) via offset
> cancellation. Whether that synthetic address equals `_req` depends
> on heap layout. The function can return 0 without dequeueing
> anything.
> 
> Walk the list with a separate `iter`. Set `req` only when a
> request matches. After the loop, `req` is NULL if nothing
> matched.
> 
> Suggested-by: Alan Stern <[email protected]>
> Signed-off-by: Maoyi Xie <[email protected]>
> ---
> v2: Switch the loop body to Alan Stern's shape: test inside
>     the if, assign `req`, break. Same behaviour as v1.
> v1: https://lore.kernel.org/linux-usb/[email protected]/
> 
>  drivers/usb/gadget/udc/aspeed_udc.c | 20 ++++++++++++--------
>  1 file changed, 12 insertions(+), 8 deletions(-)
> 
> --- a/drivers/usb/gadget/udc/aspeed_udc.c	2026-05-19 15:29:28.690931576 +0800
> +++ b/drivers/usb/gadget/udc/aspeed_udc.c	2026-05-19 15:29:59.482953528 +0800
> @@ -692,26 +692,30 @@
>  {
>  	struct ast_udc_ep *ep = to_ast_ep(_ep);
>  	struct ast_udc_dev *udc = ep->udc;
> -	struct ast_udc_request *req;
> +	struct ast_udc_request *req = NULL, *iter;
>  	unsigned long flags;
>  	int rc = 0;
>  
>  	spin_lock_irqsave(&udc->lock, flags);
>  
>  	/* make sure it's actually queued on this endpoint */
> -	list_for_each_entry(req, &ep->queue, queue) {
> -		if (&req->req == _req) {
> -			list_del_init(&req->queue);
> -			ast_udc_done(ep, req, -ESHUTDOWN);
> -			_req->status = -ECONNRESET;
> +	list_for_each_entry(iter, &ep->queue, queue) {
> +		if (&iter->req == _req) {
> +			req = iter;
>  			break;
>  		}
>  	}
>  
> -	/* dequeue request not found */
> -	if (&req->req != _req)
> +	if (!req) {
>  		rc = -EINVAL;
> +		goto out;
> +	}
> +
> +	list_del_init(&req->queue);
> +	ast_udc_done(ep, req, -ESHUTDOWN);
> +	_req->status = -ECONNRESET;
>  
> +out:
>  	spin_unlock_irqrestore(&udc->lock, flags);
>  
>  	return rc;

This is a bit of a bikeshed comment and doesn't solve making the code
similar to other cases, however: Golfing the diff a bit, perhaps we can
start from the assumption that there isn't a match, and require the
search disprove that. Then we don't have to test whether we saw
something after-the-fact, and we avoid the goto as proposed above.

Untested:

   diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c
   index 7fc6696b7694..75f9c831b21a 100644
   --- a/drivers/usb/gadget/udc/aspeed_udc.c
   +++ b/drivers/usb/gadget/udc/aspeed_udc.c
   @@ -694,7 +694,7 @@ static int ast_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
           struct ast_udc_dev *udc = ep->udc;
           struct ast_udc_request *req;
           unsigned long flags;
   -       int rc = 0;
   +       int rc = -EINVAL;
   
           spin_lock_irqsave(&udc->lock, flags);
   
   @@ -704,14 +704,11 @@ static int ast_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
                           list_del_init(&req->queue);
                           ast_udc_done(ep, req, -ESHUTDOWN);
                           _req->status = -ECONNRESET;
   +                       rc = 0;
                           break;
                   }
           }
   
   -       /* dequeue request not found */
   -       if (&req->req != _req)
   -               rc = -EINVAL;
   -
           spin_unlock_irqrestore(&udc->lock, flags);
   
           return rc;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.