The patch number 12489 was added via Mauro Carvalho Chehab <mche...@redhat.com>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        Linux Media Mailing List <linux-me...@vger.kernel.org>

------

From: Dmitry Torokhov  <dmitry.torok...@gmail.com>
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 <mche...@redhat.com>


---

 linux/drivers/media/video/pwc/pwc-if.c |   78 +++++++++++--------------
 linux/drivers/media/video/pwc/pwc.h    |    1 
 2 files changed, 36 insertions(+), 43 deletions(-)

diff -r 85799c9e14fe -r de21bb4306ef linux/drivers/media/video/pwc/pwc-if.c
--- a/linux/drivers/media/video/pwc/pwc-if.c    Tue Aug 11 00:47:29 2009 +0000
+++ b/linux/drivers/media/video/pwc/pwc-if.c    Fri Aug 14 05:22:52 2009 +0000
@@ -1065,7 +1065,8 @@
                goto err;
        if (pdev->features & FEATURE_MOTOR_PANTILT) {
                rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt);
-               if (rc) goto err_button;
+               if (rc)
+                       goto err_button;
        }
 
        return 0;
@@ -1080,6 +1081,7 @@
 static void pwc_remove_sysfs_files(struct video_device *vdev)
 {
        struct pwc_device *pdev = video_get_drvdata(vdev);
+
        if (pdev->features & FEATURE_MOTOR_PANTILT)
                device_remove_file(&vdev->dev, &dev_attr_pan_tilt);
        device_remove_file(&vdev->dev, &dev_attr_button);
@@ -1237,13 +1239,11 @@
        video_unregister_device(pdev->vdev);
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
-       if (pdev->button_dev) {
+       if (pdev->button_dev)
                input_unregister_device(pdev->button_dev);
-               input_free_device(pdev->button_dev);
-               kfree(pdev->button_dev->phys);
-               pdev->button_dev = NULL;
-       }
 #endif
+
+       kfree(pdev);
 }
 
 /* Note that all cleanup is done in the reverse order as in _open */
@@ -1289,8 +1289,6 @@
                PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
        } else {
                pwc_cleanup(pdev);
-               /* Free memory (don't set pdev to 0 just yet) */
-               kfree(pdev);
                /* search device_hint[] table if we occupy a slot, by any 
chance */
                for (hint = 0; hint < MAX_DEV_HINTS; hint++)
                        if (device_hint[hint].pdev == pdev)
@@ -1507,13 +1505,10 @@
        struct usb_device *udev = interface_to_usbdev(intf);
        struct pwc_device *pdev = NULL;
        int vendor_id, product_id, type_id;
-       int i, hint, rc;
+       int hint, rc;
        int features = 0;
        int video_nr = -1; /* default: use next available device */
        char serial_number[30], *name;
-#ifdef CONFIG_USB_PWC_INPUT_EVDEV
-       char *phys = NULL;
-#endif
 
        vendor_id = le16_to_cpu(udev->descriptor.idVendor);
        product_id = le16_to_cpu(udev->descriptor.idProduct);
@@ -1765,8 +1760,7 @@
        pdev->vframes = default_fps;
        strcpy(pdev->serial, serial_number);
        pdev->features = features;
-       if (vendor_id == 0x046D && product_id == 0x08B5)
-       {
+       if (vendor_id == 0x046D && product_id == 0x08B5) {
                /* Logitech QuickCam Orbit
                   The ranges have been determined experimentally; they may 
differ from cam to cam.
                   Also, the exact ranges left-right and up-down are different 
for my cam
@@ -1788,8 +1782,8 @@
        pdev->vdev = video_device_alloc();
        if (!pdev->vdev) {
                PWC_ERROR("Err, cannot allocate video_device struture. Failing 
probe.");
-               kfree(pdev);
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto err_free_mem;
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
        pdev->vdev->parent = &intf->dev;
@@ -1814,25 +1808,23 @@
        }
 
        pdev->vdev->release = video_device_release;
-       i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
-       if (i < 0) {
-               PWC_ERROR("Failed to register as video device (%d).\n", i);
-               rc = i;
-               goto err;
+       rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+       if (rc < 0) {
+               PWC_ERROR("Failed to register as video device (%d).\n", rc);
+               goto err_video_release;
        }
-       else {
-               PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
-       }
+
+       PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
 
        /* occupy slot */
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = pdev;
 
        PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
-       usb_set_intfdata (intf, pdev);
+       usb_set_intfdata(intf, pdev);
        rc = pwc_create_sysfs_files(pdev->vdev);
        if (rc)
-               goto err_unreg;
+               goto err_video_unreg;
 
        /* Set the leds off */
        pwc_set_leds(pdev, 0, 0);
@@ -1843,16 +1835,16 @@
        pdev->button_dev = input_allocate_device();
        if (!pdev->button_dev) {
                PWC_ERROR("Err, insufficient memory for webcam snapshot button 
device.");
-               return -ENOMEM;
+               rc = -ENOMEM;
+               pwc_remove_sysfs_files(pdev->vdev);
+               goto err_video_unreg;
        }
 
+       usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
+       strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
+
        pdev->button_dev->name = "PWC snapshot button";
-       phys = kasprintf(GFP_KERNEL,"usb-%s-%s", pdev->udev->bus->bus_name, 
pdev->udev->devpath);
-       if (!phys) {
-               input_free_device(pdev->button_dev);
-               return -ENOMEM;
-       }
-       pdev->button_dev->phys = phys;
+       pdev->button_dev->phys = pdev->button_phys;
        usb_to_input_id(pdev->udev, &pdev->button_dev->id);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
        pdev->button_dev->dev.parent = &pdev->udev->dev;
@@ -1865,25 +1857,27 @@
        rc = input_register_device(pdev->button_dev);
        if (rc) {
                input_free_device(pdev->button_dev);
-               kfree(pdev->button_dev->phys);
                pdev->button_dev = NULL;
-               return rc;
+               pwc_remove_sysfs_files(pdev->vdev);
+               goto err_video_unreg;
        }
 #endif
 
        return 0;
 
-err_unreg:
+err_video_unreg:
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = NULL;
        video_unregister_device(pdev->vdev);
-err:
-       video_device_release(pdev->vdev); /* Drip... drip... drip... */
-       kfree(pdev); /* Oops, no memory leaks please */
+       pdev->vdev = NULL;      /* So we don't try to release it below */
+err_video_release:
+       video_device_release(pdev->vdev);
+err_free_mem:
+       kfree(pdev);
        return rc;
 }
 
-/* The user janked out the cable... */
+/* The user yanked out the cable... */
 static void usb_pwc_disconnect(struct usb_interface *intf)
 {
        struct pwc_device *pdev;
@@ -1914,7 +1908,7 @@
        /* Alert waiting processes */
        wake_up_interruptible(&pdev->frameq);
        /* Wait until device is closed */
-       if(pdev->vopen) {
+       if (pdev->vopen) {
                mutex_lock(&pdev->modlock);
                pdev->unplugged = 1;
                mutex_unlock(&pdev->modlock);
@@ -1923,8 +1917,6 @@
                /* Device is closed, so we can safely unregister it */
                PWC_DEBUG_PROBE("Unregistering video device in 
disconnect().\n");
                pwc_cleanup(pdev);
-               /* Free memory (don't set pdev to 0 just yet) */
-               kfree(pdev);
 
 disconnect_out:
                /* search device_hint[] table if we occupy a slot, by any 
chance */
diff -r 85799c9e14fe -r de21bb4306ef linux/drivers/media/video/pwc/pwc.h
--- a/linux/drivers/media/video/pwc/pwc.h       Tue Aug 11 00:47:29 2009 +0000
+++ b/linux/drivers/media/video/pwc/pwc.h       Fri Aug 14 05:22:52 2009 +0000
@@ -254,6 +254,7 @@
    int snapshot_button_status;         /* set to 1 when the user push the 
button, reset to 0 when this value is read */
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
    struct input_dev *button_dev;       /* webcam snapshot button input */
+   char button_phys[64];
 #endif
 
    /*** Misc. data ***/


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/de21bb4306ef39dea3ffef2709899492ff3c5e85

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to