stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] media: uvc_driver: fix USB Camera ref leak denial of service
@ 2018-05-26 15:50 David Fries
  2018-05-26 16:21 ` Laurent Pinchart
  0 siblings, 1 reply; 4+ messages in thread
From: David Fries @ 2018-05-26 15:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: Guennadi Liakhovetski, Laurent Pinchart, Mauro Carvalho Chehab,
	stable

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@Fries.net>
Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Cc: stable@vger.kernel.org
---
 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


>From 32a612bc06a2a1b9215f3b7166342c98043bd925 Mon Sep 17 00:00:00 2001
From: David Fries <David@Fries.net>
Date: Thu, 24 May 2018 23:43:15 -0500
Subject: [PATCH] uvc_driver: UVC kref never reaches zero leading to denial of
 service

Commit 9d15cd958c17 ("media: uvcvideo: Convert from using an atomic
variable to a reference count")
didn't take into account that while the counter was
initialized to 0 (no stream open), kref_init starts with a reference
of 1, leading to the device
never reaching 0 and uvc_delete never getting called.  This leads to
evdev never getting released and /dev/input/event* eventually running
out of minors preventing any new event devices and new USB cameras from
being usable until the system is rebooted.

In my case "disabled by hub (EMI?), re-enabling..." kept
removing/inserting the device until days later it ran out of minors
and I lost the video security feed.

Now that the device is actually being removed other problems are
showing up.  Specifically the following if the camera is removed or
`rmmod ehci_pci` while an application is getting video from it.  It
doesn't happen if the camera is not in use.  How do I track that down?

sysfs group 'power' not found for kobject 'event10'
sysfs group 'power' not found for kobject 'input32'
sysfs group 'id' not found for kobject 'input32'
sysfs group 'capabilities' not found for kobject 'input32'
sysfs group 'power' not found for kobject 'media0'

Signed-off-by: David Fries <David@Fries.net>
---
 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

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/1] media: uvc_driver: fix USB Camera ref leak denial of service
  2018-05-26 15:50 [PATCH 1/1] media: uvc_driver: fix USB Camera ref leak denial of service David Fries
@ 2018-05-26 16:21 ` Laurent Pinchart
  2018-05-26 16:37   ` David Fries
  0 siblings, 1 reply; 4+ messages in thread
From: Laurent Pinchart @ 2018-05-26 16:21 UTC (permalink / raw)
  To: David Fries
  Cc: linux-kernel, Guennadi Liakhovetski, Mauro Carvalho Chehab,
	stable

Hi David,

Thank you for the patch.

On Saturday, 26 May 2018 18:50:46 EEST David Fries wrote:
> 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@Fries.net>
> Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Mauro Carvalho Chehab <mchehab@s-opensource.com>
> Cc: stable@vger.kernel.org

Philipp Zabel has already posted a similar patch, see https://
patchwork.linuxtv.org/patch/49770/

Mauro,

This is a serious issue so I'd like to get the patch merged in v4.18, but it 
could be argued that it's getting late for that, especially given that the bug 
has been there since v4.14. Would you be OK merging this in v4.18 ? If so 
could you pick https://patchwork.linuxtv.org/patch/49770/ up, or would you 
like me to send a pull request ?

> ---
>  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);
>  }

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/1] media: uvc_driver: fix USB Camera ref leak denial of service
  2018-05-26 16:21 ` Laurent Pinchart
@ 2018-05-26 16:37   ` David Fries
  2018-05-26 16:47     ` Laurent Pinchart
  0 siblings, 1 reply; 4+ messages in thread
From: David Fries @ 2018-05-26 16:37 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-kernel, Guennadi Liakhovetski, Mauro Carvalho Chehab,
	stable

Laurent and Mauro,

I've reviewed Philipp Zabel's 49770 patch, it looks like they
equivalent, but take a different path.  My version does the unref in
uvc_unregister_video, Zabel's does the unref in each caller of
uvc_unregister_video.  I think I would prefer it to be in fewer
places.

Any ideas on the sysfs group 'power' not found bug on removal while on
use?

Thanks, it will be great to get this fixed.

On Sat, May 26, 2018 at 07:21:11PM +0300, Laurent Pinchart wrote:
> Hi David,
> 
> Thank you for the patch.
> 
> On Saturday, 26 May 2018 18:50:46 EEST David Fries wrote:
> > 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@Fries.net>
> > Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Cc: Mauro Carvalho Chehab <mchehab@s-opensource.com>
> > Cc: stable@vger.kernel.org
> 
> Philipp Zabel has already posted a similar patch, see https://
> patchwork.linuxtv.org/patch/49770/
> 
> Mauro,
> 
> This is a serious issue so I'd like to get the patch merged in v4.18, but it 
> could be argued that it's getting late for that, especially given that the bug 
> has been there since v4.14. Would you be OK merging this in v4.18 ? If so 
> could you pick https://patchwork.linuxtv.org/patch/49770/ up, or would you 
> like me to send a pull request ?
> 
> > ---
> >  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);
> >  }
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> 

-- 
David Fries <david@fries.net>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/1] media: uvc_driver: fix USB Camera ref leak denial of service
  2018-05-26 16:37   ` David Fries
@ 2018-05-26 16:47     ` Laurent Pinchart
  0 siblings, 0 replies; 4+ messages in thread
From: Laurent Pinchart @ 2018-05-26 16:47 UTC (permalink / raw)
  To: David Fries
  Cc: linux-kernel, Guennadi Liakhovetski, Mauro Carvalho Chehab,
	stable

Hi David,

On Saturday, 26 May 2018 19:37:18 EEST David Fries wrote:
> Laurent and Mauro,
> 
> I've reviewed Philipp Zabel's 49770 patch, it looks like they
> equivalent, but take a different path.  My version does the unref in
> uvc_unregister_video, Zabel's does the unref in each caller of
> uvc_unregister_video.  I think I would prefer it to be in fewer
> places.

While I agree that avoiding code duplication is a good idea, we also need to 
ensure that the unref call is the very last operation we perform, otherwise 
we'll risk a use-after-free. The uvc_unregister_video() function is called 
last so that's guaranteed with your patch. However, by hiding the unref there 
from the callers, I wonder whether it couldn't result in issues in the future 
if someone decides to add code after the uvc_unregister_video() calls without 
noticing the unref issue.

> Any ideas on the sysfs group 'power' not found bug on removal while on
> use?

I haven't had time to investigate them yet, please feel free to give it a go 
without waiting for me :-)

> Thanks, it will be great to get this fixed.
> 
> On Sat, May 26, 2018 at 07:21:11PM +0300, Laurent Pinchart wrote:
> > Hi David,
> > 
> > Thank you for the patch.
> > 
> > On Saturday, 26 May 2018 18:50:46 EEST David Fries wrote:
> > > 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@Fries.net>
> > > Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > Cc: Mauro Carvalho Chehab <mchehab@s-opensource.com>
> > > Cc: stable@vger.kernel.org
> > 
> > Philipp Zabel has already posted a similar patch, see https://
> > patchwork.linuxtv.org/patch/49770/
> > 
> > Mauro,
> > 
> > This is a serious issue so I'd like to get the patch merged in v4.18, but
> > it could be argued that it's getting late for that, especially given that
> > the bug has been there since v4.14. Would you be OK merging this in v4.18
> > ? If so could you pick https://patchwork.linuxtv.org/patch/49770/ up, or
> > would you like me to send a pull request ?
> > 
> > > ---
> > > 
> > >  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);
> > >  
> > >  }


-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-05-26 16:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-05-26 15:50 [PATCH 1/1] media: uvc_driver: fix USB Camera ref leak denial of service David Fries
2018-05-26 16:21 ` Laurent Pinchart
2018-05-26 16:37   ` David Fries
2018-05-26 16:47     ` Laurent Pinchart

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).