diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-08-14 01:22:52 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-12 11:19:13 -0400 |
commit | 89dec01b7e251697720ac3d6a5310d72359eba69 (patch) | |
tree | 786097673e8e60fdc5442c1fc2ac2d65185eb1c1 /drivers/media/video/pwc | |
parent | 35c3057bb71ba0683e6f1268f3663099d8454e5f (diff) |
V4L/DVB (12489): pwc - fix few use-after-free and memory leaks
I just happen to peek inside the PWC driver and did not like what I saw
there. Please consider applying the patch below.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/pwc')
-rw-r--r-- | drivers/media/video/pwc/pwc-if.c | 78 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc.h | 1 |
2 files changed, 36 insertions, 43 deletions
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 8d17cf613306..f976df452a34 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -1057,7 +1057,8 @@ static int pwc_create_sysfs_files(struct video_device *vdev) | |||
1057 | goto err; | 1057 | goto err; |
1058 | if (pdev->features & FEATURE_MOTOR_PANTILT) { | 1058 | if (pdev->features & FEATURE_MOTOR_PANTILT) { |
1059 | rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); | 1059 | rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); |
1060 | if (rc) goto err_button; | 1060 | if (rc) |
1061 | goto err_button; | ||
1061 | } | 1062 | } |
1062 | 1063 | ||
1063 | return 0; | 1064 | return 0; |
@@ -1072,6 +1073,7 @@ err: | |||
1072 | static void pwc_remove_sysfs_files(struct video_device *vdev) | 1073 | static void pwc_remove_sysfs_files(struct video_device *vdev) |
1073 | { | 1074 | { |
1074 | struct pwc_device *pdev = video_get_drvdata(vdev); | 1075 | struct pwc_device *pdev = video_get_drvdata(vdev); |
1076 | |||
1075 | if (pdev->features & FEATURE_MOTOR_PANTILT) | 1077 | if (pdev->features & FEATURE_MOTOR_PANTILT) |
1076 | device_remove_file(&vdev->dev, &dev_attr_pan_tilt); | 1078 | device_remove_file(&vdev->dev, &dev_attr_pan_tilt); |
1077 | device_remove_file(&vdev->dev, &dev_attr_button); | 1079 | device_remove_file(&vdev->dev, &dev_attr_button); |
@@ -1229,13 +1231,11 @@ static void pwc_cleanup(struct pwc_device *pdev) | |||
1229 | video_unregister_device(pdev->vdev); | 1231 | video_unregister_device(pdev->vdev); |
1230 | 1232 | ||
1231 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV | 1233 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV |
1232 | if (pdev->button_dev) { | 1234 | if (pdev->button_dev) |
1233 | input_unregister_device(pdev->button_dev); | 1235 | input_unregister_device(pdev->button_dev); |
1234 | input_free_device(pdev->button_dev); | ||
1235 | kfree(pdev->button_dev->phys); | ||
1236 | pdev->button_dev = NULL; | ||
1237 | } | ||
1238 | #endif | 1236 | #endif |
1237 | |||
1238 | kfree(pdev); | ||
1239 | } | 1239 | } |
1240 | 1240 | ||
1241 | /* Note that all cleanup is done in the reverse order as in _open */ | 1241 | /* Note that all cleanup is done in the reverse order as in _open */ |
@@ -1281,8 +1281,6 @@ static int pwc_video_close(struct file *file) | |||
1281 | PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); | 1281 | PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); |
1282 | } else { | 1282 | } else { |
1283 | pwc_cleanup(pdev); | 1283 | pwc_cleanup(pdev); |
1284 | /* Free memory (don't set pdev to 0 just yet) */ | ||
1285 | kfree(pdev); | ||
1286 | /* search device_hint[] table if we occupy a slot, by any chance */ | 1284 | /* search device_hint[] table if we occupy a slot, by any chance */ |
1287 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) | 1285 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) |
1288 | if (device_hint[hint].pdev == pdev) | 1286 | if (device_hint[hint].pdev == pdev) |
@@ -1499,13 +1497,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1499 | struct usb_device *udev = interface_to_usbdev(intf); | 1497 | struct usb_device *udev = interface_to_usbdev(intf); |
1500 | struct pwc_device *pdev = NULL; | 1498 | struct pwc_device *pdev = NULL; |
1501 | int vendor_id, product_id, type_id; | 1499 | int vendor_id, product_id, type_id; |
1502 | int i, hint, rc; | 1500 | int hint, rc; |
1503 | int features = 0; | 1501 | int features = 0; |
1504 | int video_nr = -1; /* default: use next available device */ | 1502 | int video_nr = -1; /* default: use next available device */ |
1505 | char serial_number[30], *name; | 1503 | char serial_number[30], *name; |
1506 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV | ||
1507 | char *phys = NULL; | ||
1508 | #endif | ||
1509 | 1504 | ||
1510 | vendor_id = le16_to_cpu(udev->descriptor.idVendor); | 1505 | vendor_id = le16_to_cpu(udev->descriptor.idVendor); |
1511 | product_id = le16_to_cpu(udev->descriptor.idProduct); | 1506 | product_id = le16_to_cpu(udev->descriptor.idProduct); |
@@ -1757,8 +1752,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1757 | pdev->vframes = default_fps; | 1752 | pdev->vframes = default_fps; |
1758 | strcpy(pdev->serial, serial_number); | 1753 | strcpy(pdev->serial, serial_number); |
1759 | pdev->features = features; | 1754 | pdev->features = features; |
1760 | if (vendor_id == 0x046D && product_id == 0x08B5) | 1755 | if (vendor_id == 0x046D && product_id == 0x08B5) { |
1761 | { | ||
1762 | /* Logitech QuickCam Orbit | 1756 | /* Logitech QuickCam Orbit |
1763 | The ranges have been determined experimentally; they may differ from cam to cam. | 1757 | The ranges have been determined experimentally; they may differ from cam to cam. |
1764 | Also, the exact ranges left-right and up-down are different for my cam | 1758 | Also, the exact ranges left-right and up-down are different for my cam |
@@ -1780,8 +1774,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1780 | pdev->vdev = video_device_alloc(); | 1774 | pdev->vdev = video_device_alloc(); |
1781 | if (!pdev->vdev) { | 1775 | if (!pdev->vdev) { |
1782 | PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); | 1776 | PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); |
1783 | kfree(pdev); | 1777 | rc = -ENOMEM; |
1784 | return -ENOMEM; | 1778 | goto err_free_mem; |
1785 | } | 1779 | } |
1786 | memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); | 1780 | memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); |
1787 | pdev->vdev->parent = &intf->dev; | 1781 | pdev->vdev->parent = &intf->dev; |
@@ -1806,25 +1800,23 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1806 | } | 1800 | } |
1807 | 1801 | ||
1808 | pdev->vdev->release = video_device_release; | 1802 | pdev->vdev->release = video_device_release; |
1809 | i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); | 1803 | rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); |
1810 | if (i < 0) { | 1804 | if (rc < 0) { |
1811 | PWC_ERROR("Failed to register as video device (%d).\n", i); | 1805 | PWC_ERROR("Failed to register as video device (%d).\n", rc); |
1812 | rc = i; | 1806 | goto err_video_release; |
1813 | goto err; | ||
1814 | } | ||
1815 | else { | ||
1816 | PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num); | ||
1817 | } | 1807 | } |
1818 | 1808 | ||
1809 | PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num); | ||
1810 | |||
1819 | /* occupy slot */ | 1811 | /* occupy slot */ |
1820 | if (hint < MAX_DEV_HINTS) | 1812 | if (hint < MAX_DEV_HINTS) |
1821 | device_hint[hint].pdev = pdev; | 1813 | device_hint[hint].pdev = pdev; |
1822 | 1814 | ||
1823 | PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); | 1815 | PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); |
1824 | usb_set_intfdata (intf, pdev); | 1816 | usb_set_intfdata(intf, pdev); |
1825 | rc = pwc_create_sysfs_files(pdev->vdev); | 1817 | rc = pwc_create_sysfs_files(pdev->vdev); |
1826 | if (rc) | 1818 | if (rc) |
1827 | goto err_unreg; | 1819 | goto err_video_unreg; |
1828 | 1820 | ||
1829 | /* Set the leds off */ | 1821 | /* Set the leds off */ |
1830 | pwc_set_leds(pdev, 0, 0); | 1822 | pwc_set_leds(pdev, 0, 0); |
@@ -1835,16 +1827,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1835 | pdev->button_dev = input_allocate_device(); | 1827 | pdev->button_dev = input_allocate_device(); |
1836 | if (!pdev->button_dev) { | 1828 | if (!pdev->button_dev) { |
1837 | PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); | 1829 | PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); |
1838 | return -ENOMEM; | 1830 | rc = -ENOMEM; |
1831 | pwc_remove_sysfs_files(pdev->vdev); | ||
1832 | goto err_video_unreg; | ||
1839 | } | 1833 | } |
1840 | 1834 | ||
1835 | usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys)); | ||
1836 | strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys)); | ||
1837 | |||
1841 | pdev->button_dev->name = "PWC snapshot button"; | 1838 | pdev->button_dev->name = "PWC snapshot button"; |
1842 | phys = kasprintf(GFP_KERNEL,"usb-%s-%s", pdev->udev->bus->bus_name, pdev->udev->devpath); | 1839 | pdev->button_dev->phys = pdev->button_phys; |
1843 | if (!phys) { | ||
1844 | input_free_device(pdev->button_dev); | ||
1845 | return -ENOMEM; | ||
1846 | } | ||
1847 | pdev->button_dev->phys = phys; | ||
1848 | usb_to_input_id(pdev->udev, &pdev->button_dev->id); | 1840 | usb_to_input_id(pdev->udev, &pdev->button_dev->id); |
1849 | pdev->button_dev->dev.parent = &pdev->udev->dev; | 1841 | pdev->button_dev->dev.parent = &pdev->udev->dev; |
1850 | pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY); | 1842 | pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY); |
@@ -1853,25 +1845,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1853 | rc = input_register_device(pdev->button_dev); | 1845 | rc = input_register_device(pdev->button_dev); |
1854 | if (rc) { | 1846 | if (rc) { |
1855 | input_free_device(pdev->button_dev); | 1847 | input_free_device(pdev->button_dev); |
1856 | kfree(pdev->button_dev->phys); | ||
1857 | pdev->button_dev = NULL; | 1848 | pdev->button_dev = NULL; |
1858 | return rc; | 1849 | pwc_remove_sysfs_files(pdev->vdev); |
1850 | goto err_video_unreg; | ||
1859 | } | 1851 | } |
1860 | #endif | 1852 | #endif |
1861 | 1853 | ||
1862 | return 0; | 1854 | return 0; |
1863 | 1855 | ||
1864 | err_unreg: | 1856 | err_video_unreg: |
1865 | if (hint < MAX_DEV_HINTS) | 1857 | if (hint < MAX_DEV_HINTS) |
1866 | device_hint[hint].pdev = NULL; | 1858 | device_hint[hint].pdev = NULL; |
1867 | video_unregister_device(pdev->vdev); | 1859 | video_unregister_device(pdev->vdev); |
1868 | err: | 1860 | pdev->vdev = NULL; /* So we don't try to release it below */ |
1869 | video_device_release(pdev->vdev); /* Drip... drip... drip... */ | 1861 | err_video_release: |
1870 | kfree(pdev); /* Oops, no memory leaks please */ | 1862 | video_device_release(pdev->vdev); |
1863 | err_free_mem: | ||
1864 | kfree(pdev); | ||
1871 | return rc; | 1865 | return rc; |
1872 | } | 1866 | } |
1873 | 1867 | ||
1874 | /* The user janked out the cable... */ | 1868 | /* The user yanked out the cable... */ |
1875 | static void usb_pwc_disconnect(struct usb_interface *intf) | 1869 | static void usb_pwc_disconnect(struct usb_interface *intf) |
1876 | { | 1870 | { |
1877 | struct pwc_device *pdev; | 1871 | struct pwc_device *pdev; |
@@ -1902,7 +1896,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf) | |||
1902 | /* Alert waiting processes */ | 1896 | /* Alert waiting processes */ |
1903 | wake_up_interruptible(&pdev->frameq); | 1897 | wake_up_interruptible(&pdev->frameq); |
1904 | /* Wait until device is closed */ | 1898 | /* Wait until device is closed */ |
1905 | if(pdev->vopen) { | 1899 | if (pdev->vopen) { |
1906 | mutex_lock(&pdev->modlock); | 1900 | mutex_lock(&pdev->modlock); |
1907 | pdev->unplugged = 1; | 1901 | pdev->unplugged = 1; |
1908 | mutex_unlock(&pdev->modlock); | 1902 | mutex_unlock(&pdev->modlock); |
@@ -1911,8 +1905,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf) | |||
1911 | /* Device is closed, so we can safely unregister it */ | 1905 | /* Device is closed, so we can safely unregister it */ |
1912 | PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); | 1906 | PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); |
1913 | pwc_cleanup(pdev); | 1907 | pwc_cleanup(pdev); |
1914 | /* Free memory (don't set pdev to 0 just yet) */ | ||
1915 | kfree(pdev); | ||
1916 | 1908 | ||
1917 | disconnect_out: | 1909 | disconnect_out: |
1918 | /* search device_hint[] table if we occupy a slot, by any chance */ | 1910 | /* search device_hint[] table if we occupy a slot, by any chance */ |
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 844565bde53b..0902355dfa77 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h | |||
@@ -253,6 +253,7 @@ struct pwc_device | |||
253 | int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */ | 253 | int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */ |
254 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV | 254 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV |
255 | struct input_dev *button_dev; /* webcam snapshot button input */ | 255 | struct input_dev *button_dev; /* webcam snapshot button input */ |
256 | char button_phys[64]; | ||
256 | #endif | 257 | #endif |
257 | 258 | ||
258 | /*** Misc. data ***/ | 259 | /*** Misc. data ***/ |