Skip to content

Commit a9ea1a3

Browse files
ribaldamchehab
authored andcommitted
media: uvcvideo: Fix crash during unbind if gpio unit is in use
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: stable@vger.kernel.org Fixes: 2886477 ("media: uvcvideo: Implement UVC_EXT_GPIO_UNIT") Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Link: https://lore.kernel.org/r/20241106-uvc-crashrmmod-v6-1-fbf9781c6e83@chromium.org Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
1 parent 3365603 commit a9ea1a3

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

drivers/media/usb/uvc/uvc_driver.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,14 +1295,14 @@ static int uvc_gpio_parse(struct uvc_device *dev)
12951295
struct gpio_desc *gpio_privacy;
12961296
int irq;
12971297

1298-
gpio_privacy = devm_gpiod_get_optional(&dev->udev->dev, "privacy",
1298+
gpio_privacy = devm_gpiod_get_optional(&dev->intf->dev, "privacy",
12991299
GPIOD_IN);
13001300
if (IS_ERR_OR_NULL(gpio_privacy))
13011301
return PTR_ERR_OR_ZERO(gpio_privacy);
13021302

13031303
irq = gpiod_to_irq(gpio_privacy);
13041304
if (irq < 0)
1305-
return dev_err_probe(&dev->udev->dev, irq,
1305+
return dev_err_probe(&dev->intf->dev, irq,
13061306
"No IRQ for privacy GPIO\n");
13071307

13081308
unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT,
@@ -1329,15 +1329,27 @@ static int uvc_gpio_parse(struct uvc_device *dev)
13291329
static int uvc_gpio_init_irq(struct uvc_device *dev)
13301330
{
13311331
struct uvc_entity *unit = dev->gpio_unit;
1332+
int ret;
13321333

13331334
if (!unit || unit->gpio.irq < 0)
13341335
return 0;
13351336

1336-
return devm_request_threaded_irq(&dev->udev->dev, unit->gpio.irq, NULL,
1337-
uvc_gpio_irq,
1338-
IRQF_ONESHOT | IRQF_TRIGGER_FALLING |
1339-
IRQF_TRIGGER_RISING,
1340-
"uvc_privacy_gpio", dev);
1337+
ret = request_threaded_irq(unit->gpio.irq, NULL, uvc_gpio_irq,
1338+
IRQF_ONESHOT | IRQF_TRIGGER_FALLING |
1339+
IRQF_TRIGGER_RISING,
1340+
"uvc_privacy_gpio", dev);
1341+
1342+
unit->gpio.initialized = !ret;
1343+
1344+
return ret;
1345+
}
1346+
1347+
static void uvc_gpio_deinit(struct uvc_device *dev)
1348+
{
1349+
if (!dev->gpio_unit || !dev->gpio_unit->gpio.initialized)
1350+
return;
1351+
1352+
free_irq(dev->gpio_unit->gpio.irq, dev);
13411353
}
13421354

13431355
/* ------------------------------------------------------------------------
@@ -1934,6 +1946,8 @@ static void uvc_unregister_video(struct uvc_device *dev)
19341946
{
19351947
struct uvc_streaming *stream;
19361948

1949+
uvc_gpio_deinit(dev);
1950+
19371951
list_for_each_entry(stream, &dev->streams, list) {
19381952
/* Nothing to do here, continue. */
19391953
if (!video_is_registered(&stream->vdev))

drivers/media/usb/uvc/uvcvideo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ struct uvc_entity {
234234
u8 *bmControls;
235235
struct gpio_desc *gpio_privacy;
236236
int irq;
237+
bool initialized;
237238
} gpio;
238239
};
239240

0 commit comments

Comments
 (0)