This patch fixes resource reclaim in error path of acm_probe: 1. In the case of "out of memory (write urbs usb_alloc_urb)", usb_alloc_urb may fail in any iteration of the for loop. Current implementation does not properly free allocated snd->urb. 2. In the case of device_create_file(&intf->dev,&dev_attr_iCountryCodeRelDate) fail, acm->country_codes is kfreed. As a result, device_remove_file for dev_attr_wCountryCodes will not be executed in acm_disconnect. 3. This patch also improves the error handling by only reclaim successfully allocated resources instead of iterate over all entries in the for loop. Signed-off-by: Axel Lin <axel.lin@xxxxxxxxx> --- drivers/usb/class/cdc-acm.c | 40 +++++++++++++++++++++++----------------- 1 files changed, 23 insertions(+), 17 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0c2f14f..e215b9a 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -950,8 +950,9 @@ static int acm_probe(struct usb_interface *intf, int data_interface_num; unsigned long quirks; int num_rx_buf; - int i; + int i, j, k; int combined_interfaces = 0; + int retval; /* normal quirks */ quirks = (unsigned long)id->driver_info; @@ -1201,14 +1202,14 @@ made_compressed_probe: if (rcv->urb == NULL) { dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); - goto alloc_fail7; + goto alloc_fail6; } rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; rcv->instance = acm; } - for (i = 0; i < num_rx_buf; i++) { - struct acm_rb *rb = &(acm->rb[i]); + for (j = 0; j < num_rx_buf; j++) { + struct acm_rb *rb = &(acm->rb[j]); rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, &rb->dma); @@ -1218,14 +1219,14 @@ made_compressed_probe: goto alloc_fail7; } } - for (i = 0; i < ACM_NW; i++) { - struct acm_wb *snd = &(acm->wb[i]); + for (k = 0; k < ACM_NW; k++) { + struct acm_wb *snd = &(acm->wb[k]); snd->urb = usb_alloc_urb(0, GFP_KERNEL); if (snd->urb == NULL) { dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); - goto alloc_fail7; + goto alloc_fail8; } if (usb_endpoint_xfer_int(epwrite)) @@ -1242,8 +1243,8 @@ made_compressed_probe: usb_set_intfdata(intf, acm); - i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); - if (i < 0) + retval = device_create_file(&intf->dev, &dev_attr_bmCapabilities); + if (retval < 0) goto alloc_fail8; if (cfd) { /* export the country data */ @@ -1255,15 +1256,17 @@ made_compressed_probe: cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; - i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); - if (i < 0) { + retval = device_create_file(&intf->dev, + &dev_attr_wCountryCodes); + if (retval < 0) { kfree(acm->country_codes); goto skip_countries; } - i = device_create_file(&intf->dev, + retval = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); - if (i < 0) { + if (retval < 0) { + device_remove_file(&intf->dev, &dev_attr_wCountryCodes); kfree(acm->country_codes); goto skip_countries; } @@ -1296,11 +1299,14 @@ skip_countries: return 0; alloc_fail8: - for (i = 0; i < ACM_NW; i++) - usb_free_urb(acm->wb[i].urb); + while (--k >= 0) + usb_free_urb(acm->wb[k].urb); alloc_fail7: - acm_read_buffers_free(acm); - for (i = 0; i < num_rx_buf; i++) + while (--j >= 0) + usb_free_coherent(acm->dev, readsize, acm->rb[j].base, + acm->rb[j].dma); +alloc_fail6: + while (--i >= 0) usb_free_urb(acm->ru[i].urb); usb_free_urb(acm->ctrlurb); alloc_fail5: -- 1.5.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html