usb: gadget: fsl_udc_core: check allocation return value and cleanup on failure
authorNicholas Mc Guire <hofrat@osadl.org>
Thu, 30 Aug 2018 10:16:58 +0000 (12:16 +0200)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 2 Oct 2018 07:43:08 +0000 (10:43 +0300)
The allocation with fsl_alloc_request() and kmalloc() were unchecked
fixed this up with a NULL check and appropriate cleanup.

Additionally udc->ep_qh_size was reset to 0 on failure of allocation.
Similar udc->phy_mode is initially 0 (as udc_controller was
allocated with kzalloc in fsl_udc_probe()) so reset it to 0 as well
so that this function is side-effect free on failure. Not clear if
this is necessary or sensible as fsl_udc_release() probably can not
be called if fsl_udc_probe() failed - but it should not hurt.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Fixes: b504882da5 ("USB: add Freescale high-speed USB SOC device controller driver")
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/gadget/udc/fsl_udc_core.c

index be59309..845dee3 100644 (file)
@@ -2247,8 +2247,10 @@ static int struct_udc_setup(struct fsl_udc *udc,
        udc->phy_mode = pdata->phy_mode;
 
        udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL);
-       if (!udc->eps)
-               return -1;
+       if (!udc->eps) {
+               ERR("kmalloc udc endpoint status failed\n");
+               goto eps_alloc_failed;
+       }
 
        /* initialized QHs, take care of alignment */
        size = udc->max_ep * sizeof(struct ep_queue_head);
@@ -2262,8 +2264,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
                                        &udc->ep_qh_dma, GFP_KERNEL);
        if (!udc->ep_qh) {
                ERR("malloc QHs for udc failed\n");
-               kfree(udc->eps);
-               return -1;
+               goto ep_queue_alloc_failed;
        }
 
        udc->ep_qh_size = size;
@@ -2272,8 +2273,17 @@ static int struct_udc_setup(struct fsl_udc *udc,
        /* FIXME: fsl_alloc_request() ignores ep argument */
        udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
                        struct fsl_req, req);
+       if (!udc->status_req) {
+               ERR("kzalloc for udc status request failed\n");
+               goto udc_status_alloc_failed;
+       }
+
        /* allocate a small amount of memory to get valid address */
        udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+       if (!udc->status_req->req.buf) {
+               ERR("kzalloc for udc request buffer failed\n");
+               goto udc_req_buf_alloc_failed;
+       }
 
        udc->resume_state = USB_STATE_NOTATTACHED;
        udc->usb_state = USB_STATE_POWERED;
@@ -2281,6 +2291,18 @@ static int struct_udc_setup(struct fsl_udc *udc,
        udc->remote_wakeup = 0; /* default to 0 on reset */
 
        return 0;
+
+udc_req_buf_alloc_failed:
+       kfree(udc->status_req);
+udc_status_alloc_failed:
+       kfree(udc->ep_qh);
+       udc->ep_qh_size = 0;
+ep_queue_alloc_failed:
+       kfree(udc->eps);
+eps_alloc_failed:
+       udc->phy_mode = 0;
+       return -1;
+
 }
 
 /*----------------------------------------------------------------