[PATCH 1/1] media: uvc_driver: fix USB Camera ref leak denial of service

From: David Fries
Date: Sat May 26 2018 - 12:01:22 EST


Commit 9d15cd958c17 ("media: uvcvideo: Convert from using an atomic
variable to a reference count")
didn't take into account that while the old counter was initialized to
0 (no stream open), kref_init starts with a reference of 1. The
reference count on unplug no longer reaches 0, uvc_delete isn't
called, and evdev doesn't release /dev/input/event*. Plug and unplug
enough times and it runs out of device minors preventing any new input
device and the use of newly plugged in USB video cameras until the
system is rebooted.

Signed-off-by: David Fries <David@xxxxxxxxx>
Cc: Guennadi Liakhovetski <g.liakhovetski@xxxxxx>
Cc: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>
Cc: Mauro Carvalho Chehab <mchehab@xxxxxxxxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
---
drivers/media/usb/uvc/uvc_driver.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 2469b49..3cbdc87 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1871,13 +1871,6 @@ static void uvc_unregister_video(struct uvc_device *dev)
{
struct uvc_streaming *stream;

- /* Unregistering all video devices might result in uvc_delete() being
- * called from inside the loop if there's no open file handle. To avoid
- * that, increment the refcount before iterating over the streams and
- * decrement it when done.
- */
- kref_get(&dev->ref);
-
list_for_each_entry(stream, &dev->streams, list) {
if (!video_is_registered(&stream->vdev))
continue;
@@ -1888,6 +1881,10 @@ static void uvc_unregister_video(struct uvc_device *dev)
uvc_debugfs_cleanup_stream(stream);
}

+ /* Release the reference implicit in kref_init from uvc_probe,
+ * the UVC device won't be deleted until the last file descriptor
+ * is also closed.
+ */
kref_put(&dev->ref, uvc_delete);
}

--
2.1.4