Hi Michal,

Thank you for the patch.

On Tue, Nov 25, 2025 at 09:58, Michal Vokáč <[email protected]> wrote:

> From: Petr Beneš <[email protected]>
>
> There are two places where ci_ep->desc could be accessed despite it is
> not valid at that moment. Either the endpoint has not been enabled yet
> or it has been disabled meanwhile (The ethernet gadged behaves this way
> at least.). That results in dereferencing a null pointer.

I wonder if this is not a generic problem (that ep->desc) is reused.

Looking at usb_ep_enable() in include/linux/usb/gadget.h:

"""
static inline int usb_ep_enable(struct usb_ep *ep,
                                const struct usb_endpoint_descriptor *desc)
{
        int ret;

        if (ep->enabled)
                return 0;

        ret = ep->ops->enable(ep, desc);
        if (ret)
                return ret;
"""

Can you please explain why the generic code is not enough to handle
this?

>
> Moreover, the patch gets rid of possible outstanding requests if the
> endpoint's state changes to disabled.
>
> Signed-off-by: Petr Beneš <[email protected]>
> Signed-off-by: Michal Vokáč <[email protected]>
> ---
>  drivers/usb/gadget/ci_udc.c | 43 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>
> diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
> index 4bff75da759d..b3bbbb6ad32c 100644
> --- a/drivers/usb/gadget/ci_udc.c
> +++ b/drivers/usb/gadget/ci_udc.c
> @@ -308,6 +308,27 @@ static void ci_ep_free_request(struct usb_ep *ep, struct 
> usb_request *req)
>       free(ci_req);
>  }
>  
> +static void request_complete(struct usb_ep *ep, struct ci_req *req, int 
> status)
> +{
> +     if (req->req.status == -EINPROGRESS)
> +             req->req.status = status;
> +
> +     DBG("%s: req %p complete: status %d, actual %u\n",
> +         ep->name, req, req->req.status, req->req.actual);
> +
> +     req->req.complete(ep, &req->req);
> +}
> +
> +static void request_complete_list(struct usb_ep *ep, struct list_head *list, 
> int status)
> +{
> +     struct ci_req *req, *tmp_req;
> +
> +     list_for_each_entry_safe(req, tmp_req, list, queue) {
> +             list_del_init(&req->queue);
> +             request_complete(ep, req, status);
> +     }
> +}
> +
>  static void ep_enable(int num, int in, int maxpacket)
>  {
>       struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
> @@ -335,6 +356,12 @@ static int ci_ep_enable(struct usb_ep *ep,
>       int num, in;
>       num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
>       in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
> +
> +     if (ci_ep->desc) {
> +             DBG("%s: endpoint num %d in %d already enabled\n", __func__, 
> num, in);
> +             return 0;
> +     }
> +
>       ci_ep->desc = desc;
>       ep->desc = desc;
>  
> @@ -385,16 +412,27 @@ static int ep_disable(int num, int in)
>  static int ci_ep_disable(struct usb_ep *ep)
>  {
>       struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
> +     LIST_HEAD(req_list);
>       int num, in, err;
>  
> +     if (!ci_ep->desc) {
> +             DBG("%s: attempt to disable a not enabled yet endpoint\n", 
> __func__);
> +             goto nodesc;
> +     }
> +
>       num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
>       in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
>  
> +     list_splice_init(&ci_ep->queue, &req_list);
> +     request_complete_list(ep, &req_list, -ESHUTDOWN);
> +
>       err = ep_disable(num, in);
>       if (err)
>               return err;
>  
>       ci_ep->desc = NULL;
> +
> +nodesc:
>       ep->desc = NULL;
>       ci_ep->req_primed = false;
>       return 0;
> @@ -606,6 +644,11 @@ static int ci_ep_queue(struct usb_ep *ep,
>       int in, ret;
>       int __maybe_unused num;
>  
> +     if (!ci_ep->desc) {
> +             DBG("%s: ci_ep->desc == NULL, nothing to do!\n", __func__);
> +             return -EINVAL;
> +     }
> +
>       num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
>       in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
>  
> -- 
> 2.43.0

Reply via email to