diff options
| author | Alexey Khoroshilov <khoroshilov@ispras.ru> | 2013-03-15 17:30:32 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-03-21 18:59:01 -0400 |
| commit | c93d81955005c2ac0ea072f88d376026208410e1 (patch) | |
| tree | bae48113a39cf83c55a8f25316d5c78bdd203061 /drivers/usb/class | |
| parent | d93acbcacdec04dbdab0d1cc35457eb3bf1d2a38 (diff) | |
usb: cdc-acm: fix error handling in acm_probe()
acm_probe() ignores errors in tty_port_register_device()
and leaves intfdata pointing to freed memory on alloc_fail7
error path. The patch fixes the both issues.
Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Acked-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/class')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8ac25adf31b4..c125b61c2499 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -977,6 +977,8 @@ static int acm_probe(struct usb_interface *intf, | |||
| 977 | int num_rx_buf; | 977 | int num_rx_buf; |
| 978 | int i; | 978 | int i; |
| 979 | int combined_interfaces = 0; | 979 | int combined_interfaces = 0; |
| 980 | struct device *tty_dev; | ||
| 981 | int rv = -ENOMEM; | ||
| 980 | 982 | ||
| 981 | /* normal quirks */ | 983 | /* normal quirks */ |
| 982 | quirks = (unsigned long)id->driver_info; | 984 | quirks = (unsigned long)id->driver_info; |
| @@ -1339,11 +1341,24 @@ skip_countries: | |||
| 1339 | usb_set_intfdata(data_interface, acm); | 1341 | usb_set_intfdata(data_interface, acm); |
| 1340 | 1342 | ||
| 1341 | usb_get_intf(control_interface); | 1343 | usb_get_intf(control_interface); |
| 1342 | tty_port_register_device(&acm->port, acm_tty_driver, minor, | 1344 | tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor, |
| 1343 | &control_interface->dev); | 1345 | &control_interface->dev); |
| 1346 | if (IS_ERR(tty_dev)) { | ||
| 1347 | rv = PTR_ERR(tty_dev); | ||
| 1348 | goto alloc_fail8; | ||
| 1349 | } | ||
| 1344 | 1350 | ||
| 1345 | return 0; | 1351 | return 0; |
| 1352 | alloc_fail8: | ||
| 1353 | if (acm->country_codes) { | ||
| 1354 | device_remove_file(&acm->control->dev, | ||
| 1355 | &dev_attr_wCountryCodes); | ||
| 1356 | device_remove_file(&acm->control->dev, | ||
| 1357 | &dev_attr_iCountryCodeRelDate); | ||
| 1358 | } | ||
| 1359 | device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); | ||
| 1346 | alloc_fail7: | 1360 | alloc_fail7: |
| 1361 | usb_set_intfdata(intf, NULL); | ||
| 1347 | for (i = 0; i < ACM_NW; i++) | 1362 | for (i = 0; i < ACM_NW; i++) |
| 1348 | usb_free_urb(acm->wb[i].urb); | 1363 | usb_free_urb(acm->wb[i].urb); |
| 1349 | alloc_fail6: | 1364 | alloc_fail6: |
| @@ -1359,7 +1374,7 @@ alloc_fail2: | |||
| 1359 | acm_release_minor(acm); | 1374 | acm_release_minor(acm); |
| 1360 | kfree(acm); | 1375 | kfree(acm); |
| 1361 | alloc_fail: | 1376 | alloc_fail: |
| 1362 | return -ENOMEM; | 1377 | return rv; |
| 1363 | } | 1378 | } |
| 1364 | 1379 | ||
| 1365 | static void stop_data_traffic(struct acm *acm) | 1380 | static void stop_data_traffic(struct acm *acm) |
