On Wed Nov 6 20:36:07 2024 +0000, Ricardo Ribalda wrote:
> We used the wrong device for the device managed functions. We used the
> usb device, when we should be using the interface device.
> 
> If we unbind the driver from the usb interface, the cleanup functions
> are never called. In our case, the IRQ is never disabled.
> 
> If an IRQ is triggered, it will try to access memory sections that are
> already free, causing an OOPS.
> 
> We cannot use the function devm_request_threaded_irq here. The devm_*
> clean functions may be called after the main structure is released by
> uvc_delete.
> 
> Luckily this bug has small impact, as it is only affected by devices
> with gpio units and the user has to unbind the device, a disconnect will
> not trigger this error.
> 
> Cc: sta...@vger.kernel.org
> Fixes: 2886477ff987 ("media: uvcvideo: Implement UVC_EXT_GPIO_UNIT")
> Reviewed-by: Sergey Senozhatsky <senozhat...@chromium.org>
> Signed-off-by: Ricardo Ribalda <riba...@chromium.org>
> Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
> Link: 
> https://lore.kernel.org/r/20241106-uvc-crashrmmod-v6-1-fbf9781c6...@chromium.org
> Signed-off-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org>

Patch committed.

Thanks,
Mauro Carvalho Chehab

 drivers/media/usb/uvc/uvc_driver.c | 28 +++++++++++++++++++++-------
 drivers/media/usb/uvc/uvcvideo.h   |  1 +
 2 files changed, 22 insertions(+), 7 deletions(-)

---

diff --git a/drivers/media/usb/uvc/uvc_driver.c 
b/drivers/media/usb/uvc/uvc_driver.c
index b3c8411dc05c..5bace40bafd7 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1295,14 +1295,14 @@ static int uvc_gpio_parse(struct uvc_device *dev)
        struct gpio_desc *gpio_privacy;
        int irq;
 
-       gpio_privacy = devm_gpiod_get_optional(&dev->udev->dev, "privacy",
+       gpio_privacy = devm_gpiod_get_optional(&dev->intf->dev, "privacy",
                                               GPIOD_IN);
        if (IS_ERR_OR_NULL(gpio_privacy))
                return PTR_ERR_OR_ZERO(gpio_privacy);
 
        irq = gpiod_to_irq(gpio_privacy);
        if (irq < 0)
-               return dev_err_probe(&dev->udev->dev, irq,
+               return dev_err_probe(&dev->intf->dev, irq,
                                     "No IRQ for privacy GPIO\n");
 
        unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT,
@@ -1329,15 +1329,27 @@ static int uvc_gpio_parse(struct uvc_device *dev)
 static int uvc_gpio_init_irq(struct uvc_device *dev)
 {
        struct uvc_entity *unit = dev->gpio_unit;
+       int ret;
 
        if (!unit || unit->gpio.irq < 0)
                return 0;
 
-       return devm_request_threaded_irq(&dev->udev->dev, unit->gpio.irq, NULL,
-                                        uvc_gpio_irq,
-                                        IRQF_ONESHOT | IRQF_TRIGGER_FALLING |
-                                        IRQF_TRIGGER_RISING,
-                                        "uvc_privacy_gpio", dev);
+       ret = request_threaded_irq(unit->gpio.irq, NULL, uvc_gpio_irq,
+                                  IRQF_ONESHOT | IRQF_TRIGGER_FALLING |
+                                  IRQF_TRIGGER_RISING,
+                                  "uvc_privacy_gpio", dev);
+
+       unit->gpio.initialized = !ret;
+
+       return ret;
+}
+
+static void uvc_gpio_deinit(struct uvc_device *dev)
+{
+       if (!dev->gpio_unit || !dev->gpio_unit->gpio.initialized)
+               return;
+
+       free_irq(dev->gpio_unit->gpio.irq, dev);
 }
 
 /* ------------------------------------------------------------------------
@@ -1934,6 +1946,8 @@ static void uvc_unregister_video(struct uvc_device *dev)
 {
        struct uvc_streaming *stream;
 
+       uvc_gpio_deinit(dev);
+
        list_for_each_entry(stream, &dev->streams, list) {
                /* Nothing to do here, continue. */
                if (!video_is_registered(&stream->vdev))
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 07f9921d83f2..965a789ed03e 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -234,6 +234,7 @@ struct uvc_entity {
                        u8  *bmControls;
                        struct gpio_desc *gpio_privacy;
                        int irq;
+                       bool initialized;
                } gpio;
        };
 

Reply via email to