All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF
@ 2023-12-15 21:07 Avichal Rakesh
  2023-12-15 21:07 ` [PATCH 2/2] usb: gadget: uvc: Remove nested locking Avichal Rakesh
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Avichal Rakesh @ 2023-12-15 21:07 UTC (permalink / raw)
  To: dan.scally, gregkh, laurent.pinchart
  Cc: etalvala, jchowdhary, linux-kernel, linux-usb, Avichal Rakesh

There is a path that may lead to freed memory being referenced,
and causing kernel panics.

The kernel panic has the following stack trace:

Workqueue: uvcgadget uvcg_video_pump.c51fb85fece46625450f86adbf92c56c.cfi_jt
pstate: 60c00085 (nZCv daIf +PAN +UAO -TCO BTYPE=--)
pc : __list_del_entry_valid+0xc0/0xd4
lr : __list_del_entry_valid+0xc0/0xd4
Call trace:
  __list_del_entry_valid+0xc0/0xd4
  uvc_video_free_request+0x60/0x98
  uvcg_video_pump+0x1cc/0x204
  process_one_work+0x21c/0x4b8
  worker_thread+0x29c/0x574
  kthread+0x158/0x1b0
  ret_from_fork+0x10/0x30

The root cause is that uvcg_video_usb_req_queue frees the uvc_request
if is_enabled is false and returns an error status. video_pump also
frees the associated request if uvcg_video_usb_req_queue returns an e
rror status, leading to double free and accessing garbage memory.

To fix the issue, this patch removes freeing logic from
uvcg_video_usb_req_queue, and lets the callers to the function handle
queueing errors as they see fit.

Signed-off-by: Avichal Rakesh <arakesh@google.com>
---
 drivers/usb/gadget/function/uvc_video.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 98ba524c27f5..e5db1be14ca3 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -277,8 +277,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
 	struct list_head *list = NULL;
 
 	if (!video->is_enabled) {
-		uvc_video_free_request(req->context, video->ep);
-		return -ENODEV;
+		return -EINVAL;
 	}
 	if (queue_to_ep) {
 		struct uvc_request *ureq = req->context;
@@ -464,8 +463,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
 		 * and this thread for isoc endpoints.
 		 */
 		ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk);
-		if (ret < 0)
+		if (ret < 0) {
+			/*
+			 * Endpoint error, but the stream is still enabled.
+			 * Put request back in req_free for it to be cleaned
+			 * up later.
+			 */
 			uvcg_queue_cancel(queue, 0);
+			list_add_tail(&to_queue->list, &video->req_free);
+		}
 	} else {
 		uvc_video_free_request(ureq, ep);
 	}
-- 
2.43.0.472.g3155946c3a-goog


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

* [PATCH 2/2] usb: gadget: uvc: Remove nested locking
  2023-12-15 21:07 [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Avichal Rakesh
@ 2023-12-15 21:07 ` Avichal Rakesh
  2024-01-04 14:19   ` Greg KH
  2024-01-04 14:19 ` [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Greg KH
  2024-01-04 21:50 ` [PATCH v2 " Avichal Rakesh
  2 siblings, 1 reply; 7+ messages in thread
From: Avichal Rakesh @ 2023-12-15 21:07 UTC (permalink / raw)
  To: dan.scally, gregkh, laurent.pinchart
  Cc: etalvala, jchowdhary, linux-kernel, linux-usb, Avichal Rakesh

When handling error status from uvcg_video_usb_req_queue,
uvc_video_complete currently calls uvcg_queue_cancel with
video->req_lock held. uvcg_queue_cancel internally locks
queue->irqlock, which nests queue->irqlock inside
video->req_lock. This isn't a functional bug at the
moment, but does open up possibilities for ABBA
deadlocks in the future.

This patch fixes the accidental nesting by dropping
video->req_lock before calling uvcg_queue_cancel.

Signed-off-by: Avichal Rakesh <arakesh@google.com>
---
 drivers/usb/gadget/function/uvc_video.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index e5db1be14ca3..d15b9b4c4fcc 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -469,13 +469,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
 			 * Put request back in req_free for it to be cleaned
 			 * up later.
 			 */
-			uvcg_queue_cancel(queue, 0);
 			list_add_tail(&to_queue->list, &video->req_free);
 		}
 	} else {
 		uvc_video_free_request(ureq, ep);
+		ret = 0;
 	}
 	spin_unlock_irqrestore(&video->req_lock, flags);
+	if (ret < 0)
+		uvcg_queue_cancel(queue, 0);
 }
 
 static int
-- 
2.43.0.472.g3155946c3a-goog


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

* Re: [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF
  2023-12-15 21:07 [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Avichal Rakesh
  2023-12-15 21:07 ` [PATCH 2/2] usb: gadget: uvc: Remove nested locking Avichal Rakesh
@ 2024-01-04 14:19 ` Greg KH
  2024-01-04 21:56   ` Avichal Rakesh
  2024-01-04 21:50 ` [PATCH v2 " Avichal Rakesh
  2 siblings, 1 reply; 7+ messages in thread
From: Greg KH @ 2024-01-04 14:19 UTC (permalink / raw)
  To: Avichal Rakesh
  Cc: dan.scally, laurent.pinchart, etalvala, jchowdhary, linux-kernel,
	linux-usb

On Fri, Dec 15, 2023 at 01:07:44PM -0800, Avichal Rakesh wrote:
> There is a path that may lead to freed memory being referenced,
> and causing kernel panics.
> 
> The kernel panic has the following stack trace:
> 
> Workqueue: uvcgadget uvcg_video_pump.c51fb85fece46625450f86adbf92c56c.cfi_jt
> pstate: 60c00085 (nZCv daIf +PAN +UAO -TCO BTYPE=--)
> pc : __list_del_entry_valid+0xc0/0xd4
> lr : __list_del_entry_valid+0xc0/0xd4
> Call trace:
>   __list_del_entry_valid+0xc0/0xd4
>   uvc_video_free_request+0x60/0x98
>   uvcg_video_pump+0x1cc/0x204
>   process_one_work+0x21c/0x4b8
>   worker_thread+0x29c/0x574
>   kthread+0x158/0x1b0
>   ret_from_fork+0x10/0x30
> 
> The root cause is that uvcg_video_usb_req_queue frees the uvc_request
> if is_enabled is false and returns an error status. video_pump also
> frees the associated request if uvcg_video_usb_req_queue returns an e
> rror status, leading to double free and accessing garbage memory.

Odd line wrapping :(

> 
> To fix the issue, this patch removes freeing logic from
> uvcg_video_usb_req_queue, and lets the callers to the function handle
> queueing errors as they see fit.
> 
> Signed-off-by: Avichal Rakesh <arakesh@google.com>
> ---
>  drivers/usb/gadget/function/uvc_video.c | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)

What commit id does this fix?


> 
> diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
> index 98ba524c27f5..e5db1be14ca3 100644
> --- a/drivers/usb/gadget/function/uvc_video.c
> +++ b/drivers/usb/gadget/function/uvc_video.c
> @@ -277,8 +277,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
>  	struct list_head *list = NULL;
>  
>  	if (!video->is_enabled) {
> -		uvc_video_free_request(req->context, video->ep);
> -		return -ENODEV;
> +		return -EINVAL;

Isn't this a separate change?  And does it actually matter?

thanks,

greg k-h

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

* Re: [PATCH 2/2] usb: gadget: uvc: Remove nested locking
  2023-12-15 21:07 ` [PATCH 2/2] usb: gadget: uvc: Remove nested locking Avichal Rakesh
@ 2024-01-04 14:19   ` Greg KH
  0 siblings, 0 replies; 7+ messages in thread
From: Greg KH @ 2024-01-04 14:19 UTC (permalink / raw)
  To: Avichal Rakesh
  Cc: dan.scally, laurent.pinchart, etalvala, jchowdhary, linux-kernel,
	linux-usb

On Fri, Dec 15, 2023 at 01:07:45PM -0800, Avichal Rakesh wrote:
> When handling error status from uvcg_video_usb_req_queue,
> uvc_video_complete currently calls uvcg_queue_cancel with
> video->req_lock held. uvcg_queue_cancel internally locks
> queue->irqlock, which nests queue->irqlock inside
> video->req_lock. This isn't a functional bug at the
> moment, but does open up possibilities for ABBA
> deadlocks in the future.
> 
> This patch fixes the accidental nesting by dropping
> video->req_lock before calling uvcg_queue_cancel.
> 
> Signed-off-by: Avichal Rakesh <arakesh@google.com>
> ---
>  drivers/usb/gadget/function/uvc_video.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)

Again, what commit does this fix?

thanks,

greg k-h

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

* [PATCH v2 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF
  2023-12-15 21:07 [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Avichal Rakesh
  2023-12-15 21:07 ` [PATCH 2/2] usb: gadget: uvc: Remove nested locking Avichal Rakesh
  2024-01-04 14:19 ` [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Greg KH
@ 2024-01-04 21:50 ` Avichal Rakesh
  2024-01-04 21:50   ` [PATCH v2 2/2] usb: gadget: uvc: Remove nested locking Avichal Rakesh
  2 siblings, 1 reply; 7+ messages in thread
From: Avichal Rakesh @ 2024-01-04 21:50 UTC (permalink / raw)
  To: arakesh, gregkh
  Cc: dan.scally, etalvala, jchowdhary, laurent.pinchart, linux-kernel,
	linux-usb

There is a path that may lead to freed memory being referenced,
causing kernel panics.

The kernel panic has the following stack trace:

Workqueue: uvcgadget uvcg_video_pump.c51fb85fece46625450f86adbf92c56c.cfi_jt
pstate: 60c00085 (nZCv daIf +PAN +UAO -TCO BTYPE=--)
pc : __list_del_entry_valid+0xc0/0xd4
lr : __list_del_entry_valid+0xc0/0xd4
Call trace:
  __list_del_entry_valid+0xc0/0xd4
  uvc_video_free_request+0x60/0x98
  uvcg_video_pump+0x1cc/0x204
  process_one_work+0x21c/0x4b8
  worker_thread+0x29c/0x574
  kthread+0x158/0x1b0
  ret_from_fork+0x10/0x30

The root cause is that uvcg_video_usb_req_queue frees the uvc_request
if is_enabled is false and returns an error status. video_pump also
frees the associated request if uvcg_video_usb_req_queue returns an
error status, leading to double free and accessing garbage memory.

To fix the issue, this patch removes freeing logic from
uvcg_video_usb_req_queue, and lets the callers to the function handle
queueing errors as they see fit.

Fixes: 6acba0345b68 ("usb:gadget:uvc Do not use worker thread to pump isoc usb requests")
Tested-by: Avichal Rakesh <arakesh@google.com>
Signed-off-by: Avichal Rakesh <arakesh@google.com>
---
v1 -> v2: Address review comment; add "Fixes" tag; fix goofy line wrap

 drivers/usb/gadget/function/uvc_video.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 98ba524c27f5..7f18dc471be3 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -276,10 +276,9 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
 	bool is_bulk = video->max_payload_size;
 	struct list_head *list = NULL;

-	if (!video->is_enabled) {
-		uvc_video_free_request(req->context, video->ep);
+	if (!video->is_enabled)
 		return -ENODEV;
-	}
+
 	if (queue_to_ep) {
 		struct uvc_request *ureq = req->context;
 		/*
@@ -464,8 +463,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
 		 * and this thread for isoc endpoints.
 		 */
 		ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk);
-		if (ret < 0)
+		if (ret < 0) {
+			/*
+			 * Endpoint error, but the stream is still enabled.
+			 * Put request back in req_free for it to be cleaned
+			 * up later.
+			 */
 			uvcg_queue_cancel(queue, 0);
+			list_add_tail(&to_queue->list, &video->req_free);
+		}
 	} else {
 		uvc_video_free_request(ureq, ep);
 	}
--
2.43.0.472.g3155946c3a-goog

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

* [PATCH v2 2/2] usb: gadget: uvc: Remove nested locking
  2024-01-04 21:50 ` [PATCH v2 " Avichal Rakesh
@ 2024-01-04 21:50   ` Avichal Rakesh
  0 siblings, 0 replies; 7+ messages in thread
From: Avichal Rakesh @ 2024-01-04 21:50 UTC (permalink / raw)
  To: arakesh, gregkh
  Cc: dan.scally, etalvala, jchowdhary, laurent.pinchart, linux-kernel,
	linux-usb

When handling error status from uvcg_video_usb_req_queue,
uvc_video_complete currently calls uvcg_queue_cancel with
video->req_lock held. uvcg_queue_cancel internally locks
queue->irqlock, which nests queue->irqlock inside
video->req_lock. This isn't a functional bug at the
moment, but does open up possibilities for ABBA
deadlocks in the future.

This patch fixes the accidental nesting by dropping
video->req_lock before calling uvcg_queue_cancel.

Fixes: 6acba0345b68 ("usb:gadget:uvc Do not use worker thread to pump isoc usb requests")
Signed-off-by: Avichal Rakesh <arakesh@google.com>
---
v1 -> v2: Add "Fixes" tag.

 drivers/usb/gadget/function/uvc_video.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 7f18dc471be3..dd3241fc6939 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -469,13 +469,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
 			 * Put request back in req_free for it to be cleaned
 			 * up later.
 			 */
-			uvcg_queue_cancel(queue, 0);
 			list_add_tail(&to_queue->list, &video->req_free);
 		}
 	} else {
 		uvc_video_free_request(ureq, ep);
+		ret = 0;
 	}
 	spin_unlock_irqrestore(&video->req_lock, flags);
+	if (ret < 0)
+		uvcg_queue_cancel(queue, 0);
 }

 static int
--
2.43.0.472.g3155946c3a-goog

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

* Re: [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF
  2024-01-04 14:19 ` [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Greg KH
@ 2024-01-04 21:56   ` Avichal Rakesh
  0 siblings, 0 replies; 7+ messages in thread
From: Avichal Rakesh @ 2024-01-04 21:56 UTC (permalink / raw)
  To: Greg KH
  Cc: dan.scally, laurent.pinchart, etalvala, jchowdhary, linux-kernel,
	linux-usb

Thank you for the review, Greg!

Sent out V2 with the comments addressed.

On 1/4/24 06:19, Greg KH wrote:
> On Fri, Dec 15, 2023 at 01:07:44PM -0800, Avichal Rakesh wrote:
>> There is a path that may lead to freed memory being referenced,
>> and causing kernel panics.
>>
>> The kernel panic has the following stack trace:
>>
>> Workqueue: uvcgadget uvcg_video_pump.c51fb85fece46625450f86adbf92c56c.cfi_jt
>> pstate: 60c00085 (nZCv daIf +PAN +UAO -TCO BTYPE=--)
>> pc : __list_del_entry_valid+0xc0/0xd4
>> lr : __list_del_entry_valid+0xc0/0xd4
>> Call trace:
>>   __list_del_entry_valid+0xc0/0xd4
>>   uvc_video_free_request+0x60/0x98
>>   uvcg_video_pump+0x1cc/0x204
>>   process_one_work+0x21c/0x4b8
>>   worker_thread+0x29c/0x574
>>   kthread+0x158/0x1b0
>>   ret_from_fork+0x10/0x30
>>
>> The root cause is that uvcg_video_usb_req_queue frees the uvc_request
>> if is_enabled is false and returns an error status. video_pump also
>> frees the associated request if uvcg_video_usb_req_queue returns an e
>> rror status, leading to double free and accessing garbage memory.
> 
> Odd line wrapping :(

Sigh! Fixed. Apologies.

> 
>>
>> To fix the issue, this patch removes freeing logic from
>> uvcg_video_usb_req_queue, and lets the callers to the function handle
>> queueing errors as they see fit.
>>
>> Signed-off-by: Avichal Rakesh <arakesh@google.com>
>> ---
>>  drivers/usb/gadget/function/uvc_video.c | 12 +++++++++---
>>  1 file changed, 9 insertions(+), 3 deletions(-)
> 
> What commit id does this fix?

The commit that caused the bug is not in linus' branch yet. Added
the "Fixes" tag with the commit SHA from usb-next branch. Let me know
if I should be using some other SHA.

> 
> 
>>
>> diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
>> index 98ba524c27f5..e5db1be14ca3 100644
>> --- a/drivers/usb/gadget/function/uvc_video.c
>> +++ b/drivers/usb/gadget/function/uvc_video.c
>> @@ -277,8 +277,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
>>  	struct list_head *list = NULL;
>>  
>>  	if (!video->is_enabled) {
>> -		uvc_video_free_request(req->context, video->ep);
>> -		return -ENODEV;
>> +		return -EINVAL;
> 
> Isn't this a separate change?  And does it actually matter?

It was meant to differentiate between usb_ep_queue failing 
and the video stream being disabled, but we don't really
care about that. Reverted.

Thank you!

- Avi.

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

end of thread, other threads:[~2024-01-04 21:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-15 21:07 [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Avichal Rakesh
2023-12-15 21:07 ` [PATCH 2/2] usb: gadget: uvc: Remove nested locking Avichal Rakesh
2024-01-04 14:19   ` Greg KH
2024-01-04 14:19 ` [PATCH 1/2] usb: gadget: uvc: Fix use are free during STREAMOFF Greg KH
2024-01-04 21:56   ` Avichal Rakesh
2024-01-04 21:50 ` [PATCH v2 " Avichal Rakesh
2024-01-04 21:50   ` [PATCH v2 2/2] usb: gadget: uvc: Remove nested locking Avichal Rakesh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.