Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: UDC: net2272: Fix memory leaks

Like net2280 (on which it was based), the net2272 UDC driver has a
problem with leaking memory along some of its failure pathways. It
also has another problem, not previously noted, in that some of the
failure pathways will call usb_del_gadget_udc() without first calling
usb_add_gadget_udc_release(). And it leaks memory by calling kfree()
when it should call put_device().

Until now it has been impossible to handle the memory leaks, because of
lack of support in the UDC core for separately initializing and adding
gadgets, or for separately deleting and freeing gadgets. An earlier
patch in this series adds the necessary support, making it possible to
fix the outstanding problems properly.

This patch adds an "added" flag to the net2272 structure to indicate
whether or not the gadget has been registered (and thus whether or not
to call usb_del_gadget()), and it fixes the deallocation issues by
calling usb_put_gadget() at the appropriate places.

A similar memory leak issue, apparently never before recognized, stems
from the fact that the driver never initializes the drvdata field in
the gadget's embedded struct device! Evidently this wasn't noticed
because the pointer is only ever used as an argument to kfree(), which
doesn't mind getting called with a NULL pointer. In fact, the drvdata
for gadget device will be written by usb_composite_dev structure if
any gadget class is loaded, so it needs to use usb_gadget structure
to get net2280 private data.

CC: Anton Vasilyev <vasilyev@ispras.ru>
CC: Evgeny Novikov <novikov@ispras.ru>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Peter Chen <peter.chen@nxp.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>

authored by

Alan Stern and committed by
Felipe Balbi
9b719c71 f770fbec

+14 -10
+13 -10
drivers/usb/gadget/udc/net2272.c
··· 2195 2195 static void 2196 2196 net2272_gadget_release(struct device *_dev) 2197 2197 { 2198 - struct net2272 *dev = dev_get_drvdata(_dev); 2198 + struct net2272 *dev = container_of(_dev, struct net2272, gadget.dev); 2199 + 2199 2200 kfree(dev); 2200 2201 } 2201 2202 ··· 2205 2204 static void 2206 2205 net2272_remove(struct net2272 *dev) 2207 2206 { 2208 - usb_del_gadget_udc(&dev->gadget); 2207 + if (dev->added) 2208 + usb_del_gadget(&dev->gadget); 2209 2209 free_irq(dev->irq, dev); 2210 2210 iounmap(dev->base_addr); 2211 2211 device_remove_file(dev->dev, &dev_attr_registers); ··· 2236 2234 2237 2235 /* the "gadget" abstracts/virtualizes the controller */ 2238 2236 ret->gadget.name = driver_name; 2237 + usb_initialize_gadget(dev, &ret->gadget, net2272_gadget_release); 2239 2238 2240 2239 return ret; 2241 2240 } ··· 2275 2272 if (ret) 2276 2273 goto err_irq; 2277 2274 2278 - ret = usb_add_gadget_udc_release(dev->dev, &dev->gadget, 2279 - net2272_gadget_release); 2275 + ret = usb_add_gadget(&dev->gadget); 2280 2276 if (ret) 2281 2277 goto err_add_udc; 2278 + dev->added = 1; 2282 2279 2283 2280 return 0; 2284 2281 ··· 2453 2450 2454 2451 if (pci_enable_device(pdev) < 0) { 2455 2452 ret = -ENODEV; 2456 - goto err_free; 2453 + goto err_put; 2457 2454 } 2458 2455 2459 2456 pci_set_master(pdev); ··· 2476 2473 2477 2474 err_pci: 2478 2475 pci_disable_device(pdev); 2479 - err_free: 2480 - kfree(dev); 2476 + err_put: 2477 + usb_put_gadget(&dev->gadget); 2481 2478 2482 2479 return ret; 2483 2480 } ··· 2538 2535 2539 2536 pci_disable_device(pdev); 2540 2537 2541 - kfree(dev); 2538 + usb_put_gadget(&dev->gadget); 2542 2539 } 2543 2540 2544 2541 /* Table of matching PCI IDs */ ··· 2651 2648 err_req: 2652 2649 release_mem_region(base, len); 2653 2650 err: 2654 - kfree(dev); 2651 + usb_put_gadget(&dev->gadget); 2655 2652 2656 2653 return ret; 2657 2654 } ··· 2666 2663 release_mem_region(pdev->resource[0].start, 2667 2664 resource_size(&pdev->resource[0])); 2668 2665 2669 - kfree(dev); 2666 + usb_put_gadget(&dev->gadget); 2670 2667 2671 2668 return 0; 2672 2669 }
+1
drivers/usb/gadget/udc/net2272.h
··· 441 441 unsigned protocol_stall:1, 442 442 softconnect:1, 443 443 wakeup:1, 444 + added:1, 444 445 dma_eot_polarity:1, 445 446 dma_dack_polarity:1, 446 447 dma_dreq_polarity:1,