diff options
author | Yongsul Oh <yongsul96.oh@samsung.com> | 2012-03-20 10:38:38 +0900 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-05-04 15:53:06 +0300 |
commit | 124ef389256f71042ab5dedde98dee5e9999a635 (patch) | |
tree | 1473efbd86a1e4c30c87dcd66b0bd9365daba493 /drivers/usb/gadget/composite.c | |
parent | c2484606a105e35a9bbbfafa41ee32683b82cf5a (diff) | |
download | talos-obmc-linux-124ef389256f71042ab5dedde98dee5e9999a635.tar.gz talos-obmc-linux-124ef389256f71042ab5dedde98dee5e9999a635.zip |
usb: gadget: composite: prevent a memory leak when configuration bind fails
In some USB composite gadget drivers, the configuration's bind function called
by the usb_add_config() calls multiple bind config functions. (for example cdc2
configuration bind function in the cdc_do_config() of the cdc2.c has two
functionality bind config functions.
- the ecm_bind_config() & the acm_bind_config())
In each functionality bind config function, new instance is allocated and
finally added by the usb_add_function().
So if an error occurred during the second functionality bind config (for
example an error occurred at the acm_bind_config() after succeeding of the
ecm_bind_function()), the instance created by the acm_bind_config() cannot be
freed creating a memory leak.
This patch fixes this issue.
Signed-off-by: Yongsul Oh <yongsul96.oh@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r-- | drivers/usb/gadget/composite.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index baaebf2830fc..4cb1801539a6 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -737,6 +737,19 @@ int usb_add_config(struct usb_composite_dev *cdev, status = bind(config); if (status < 0) { + while (!list_empty(&config->functions)) { + struct usb_function *f; + + f = list_first_entry(&config->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + DBG(cdev, "unbind function '%s'/%p\n", + f->name, f); + f->unbind(config, f); + /* may free memory for "f" */ + } + } list_del(&config->list); config->cdev = NULL; } else { |