From nobody Wed Jan 7 03:59:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 32B4DCDB47E for ; Wed, 18 Oct 2023 19:46:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231327AbjJRTqr (ORCPT ); Wed, 18 Oct 2023 15:46:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58870 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229963AbjJRTqq (ORCPT ); Wed, 18 Oct 2023 15:46:46 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4EF5B112 for ; Wed, 18 Oct 2023 12:46:44 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-5a88f9a1cf7so49525257b3.3 for ; Wed, 18 Oct 2023 12:46:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1697658403; x=1698263203; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=wazq6oxL63t4WK65yHIQsChGr02y7yPq4mkDkJPS1lI=; b=yBuI7vqGYV937YH8bRXnsQBr7GgLNVJW87gdSZ5VZVSHNuVzCwV8O41Y5BId7ZlzlN JICtdvUfmA56jjsdN5is6jtqaEiPBCv/M6JJaIYCKXxcif1rQXSBnWqILNgNHUaI6iH0 I4pS+C0TL7pKGDuUkmsF05dNws6zYjqEiTsc+GTqHfmoJ6Dy4aPx5IjzFpilG5C9xDX4 zLiOKWH7//7DLGBRhfwpXrJ/Cpts869a/8aQoandLd9fcimoHaCv7SkS+1B/iwDdHMq/ UQx1ZCX+lnheQNqLJybJmt8UvkDzxVBwLtE/WkQxV0gN2M9ntmCQy6kdgcaWyWsboUlJ NbEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697658403; x=1698263203; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=wazq6oxL63t4WK65yHIQsChGr02y7yPq4mkDkJPS1lI=; b=qXv+7uoXg9EBEFijAFkCgVVVSzWhCcgVD4NxggX2DGeaPPo7uWZAQZdmgULX4t3Kwe VXl/QjEU0ndEE06Rt9DoCbQFcq6M9SKVL/EH8o6AHwP+SmIzgf+X0OGR+P/+2feDW+Q0 BhNhbmddCb/IP8gS5gwXZCD4c+DoaIfyA67V+mQfd+q0nqfroWhl7BGcklbV7FlQon/H afUkurB1Df2ea6vPXeuF7cR9kFJjHemeW+aH/IA5/LkxPN2iozxECc3b+yaBKsv5GoFs 5HFVIm9wj3bJ1VSGZybrpMaLPkjKn78h2L6hn0uCr7vIXgA++z2e5572iIX4WxWuDfBI meHw== X-Gm-Message-State: AOJu0Yx71bKpHau+iKU7vZoy4M91mHd1/fsex17FeUh3hl/7lR0ZsaDf N6ceZ8MwXasq1wceZ6y5DKOFfbjj9xUz X-Google-Smtp-Source: AGHT+IG8AcCB3JfVpB3VCsrBZOxctE7QIMb3NeGNL9VMrYruPW7eR7/H71EE/aqE4bot844Rim6PoZy72OoI X-Received: from hi-h2o-specialist.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:3cef]) (user=arakesh job=sendgmr) by 2002:a05:6902:52:b0:d9b:f88c:ca2b with SMTP id m18-20020a056902005200b00d9bf88cca2bmr8249ybh.11.1697658403560; Wed, 18 Oct 2023 12:46:43 -0700 (PDT) Date: Wed, 18 Oct 2023 12:46:36 -0700 In-Reply-To: <20230930184821.310143-1-arakesh@google.com> Mime-Version: 1.0 References: <20230930184821.310143-1-arakesh@google.com> X-Mailer: git-send-email 2.42.0.758.gaed0368e0e-goog Message-ID: <20231018194638.2446575-1-arakesh@google.com> Subject: [PATCH v5 1/3] usb: gadget: uvc: prevent use of disabled endpoint From: Avichal Rakesh To: arakesh@google.com, dan.scally@ideasonboard.com, gregkh@linuxfoundation.org, laurent.pinchart@ideasonboard.com, m.grzeschik@pengutronix.de Cc: etalvala@google.com, jchowdhary@google.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently the set_alt callback immediately disables the endpoint and queues the v4l2 streamoff event. However, as the streamoff event is processed asynchronously, it is possible that the video_pump thread attempts to queue requests to an already disabled endpoint. This change moves disabling usb endpoint to the end of streamoff event callback. As the endpoint's state can no longer be used, video_pump is now guarded by uvc->state as well. To be consistent with the actual streaming state, uvc->state is now toggled between CONNECTED and STREAMING from the v4l2 event callback only. Link: https://lore.kernel.org/20230615171558.GK741@pendragon.ideasonboard.c= om/ Link: https://lore.kernel.org/20230531085544.253363-1-dan.scally@ideasonboa= rd.com/ Reviewed-by: Michael Grzeschik Tested-by: Michael Grzeschik Signed-off-by: Avichal Rakesh --- v1 -> v2: Rebased to ToT and reworded commit message. v2 -> v3: Fix email threading goof-up v3 -> v4: Address review comments & re-rebase to ToT v4 -> v5: Add Reviewed-by & Tested-by drivers/usb/gadget/function/f_uvc.c | 11 +++++------ drivers/usb/gadget/function/f_uvc.h | 2 +- drivers/usb/gadget/function/uvc.h | 2 +- drivers/usb/gadget/function/uvc_v4l2.c | 20 +++++++++++++++++--- drivers/usb/gadget/function/uvc_video.c | 3 ++- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/funct= ion/f_uvc.c index faa398109431..ae08341961eb 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -263,10 +263,13 @@ uvc_function_setup(struct usb_function *f, const stru= ct usb_ctrlrequest *ctrl) return 0; } -void uvc_function_setup_continue(struct uvc_device *uvc) +void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep) { struct usb_composite_dev *cdev =3D uvc->func.config->cdev; + if (disable_ep && uvc->video.ep) + usb_ep_disable(uvc->video.ep); + usb_composite_setup_continue(cdev); } @@ -337,15 +340,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned= interface, unsigned alt) if (uvc->state !=3D UVC_STATE_STREAMING) return 0; - if (uvc->video.ep) - usb_ep_disable(uvc->video.ep); - memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type =3D UVC_EVENT_STREAMOFF; v4l2_event_queue(&uvc->vdev, &v4l2_event); - uvc->state =3D UVC_STATE_CONNECTED; - return 0; + return USB_GADGET_DELAYED_STATUS; case 1: if (uvc->state !=3D UVC_STATE_CONNECTED) diff --git a/drivers/usb/gadget/function/f_uvc.h b/drivers/usb/gadget/funct= ion/f_uvc.h index 1db972d4beeb..e7f9f13f14dc 100644 --- a/drivers/usb/gadget/function/f_uvc.h +++ b/drivers/usb/gadget/function/f_uvc.h @@ -11,7 +11,7 @@ struct uvc_device; -void uvc_function_setup_continue(struct uvc_device *uvc); +void uvc_function_setup_continue(struct uvc_device *uvc, int disale_ep); void uvc_function_connect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/functio= n/uvc.h index 6751de8b63ad..989bc6b4e93d 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -177,7 +177,7 @@ struct uvc_file_handle { * Functions */ -extern void uvc_function_setup_continue(struct uvc_device *uvc); +extern void uvc_function_setup_continue(struct uvc_device *uvc, int disabl= e_ep); extern void uvc_function_connect(struct uvc_device *uvc); extern void uvc_function_disconnect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/fu= nction/uvc_v4l2.c index 3f0a9795c0d4..7cb8d027ff0c 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -451,7 +451,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l= 2_buf_type type) * Complete the alternate setting selection setup phase now that * userspace is ready to provide video frames. */ - uvc_function_setup_continue(uvc); + uvc_function_setup_continue(uvc, 0); uvc->state =3D UVC_STATE_STREAMING; return 0; @@ -463,11 +463,18 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum = v4l2_buf_type type) struct video_device *vdev =3D video_devdata(file); struct uvc_device *uvc =3D video_get_drvdata(vdev); struct uvc_video *video =3D &uvc->video; + int ret =3D 0; if (type !=3D video->queue.queue.type) return -EINVAL; - return uvcg_video_enable(video, 0); + uvc->state =3D UVC_STATE_CONNECTED; + ret =3D uvcg_video_enable(video, 0); + if (ret < 0) + return ret; + + uvc_function_setup_continue(uvc, 1); + return 0; } static int @@ -500,6 +507,14 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh, static void uvc_v4l2_disable(struct uvc_device *uvc) { uvc_function_disconnect(uvc); + /* + * Drop uvc->state to CONNECTED if it was streaming before. + * This ensures that the usb_requests are no longer queued + * to the controller. + */ + if (uvc->state =3D=3D UVC_STATE_STREAMING) + uvc->state =3D UVC_STATE_CONNECTED; + uvcg_video_enable(&uvc->video, 0); uvcg_free_buffers(&uvc->video.queue); uvc->func_connected =3D false; @@ -647,4 +662,3 @@ const struct v4l2_file_operations uvc_v4l2_fops =3D { .get_unmapped_area =3D uvcg_v4l2_get_unmapped_area, #endif }; - diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/f= unction/uvc_video.c index 91af3b1ef0d4..c334802ac0a4 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -384,13 +384,14 @@ static void uvcg_video_pump(struct work_struct *work) struct uvc_video_queue *queue =3D &video->queue; /* video->max_payload_size is only set when using bulk transfer */ bool is_bulk =3D video->max_payload_size; + struct uvc_device *uvc =3D video->uvc; struct usb_request *req =3D NULL; struct uvc_buffer *buf; unsigned long flags; bool buf_done; int ret; - while (video->ep->enabled) { + while (uvc->state =3D=3D UVC_STATE_STREAMING && video->ep->enabled) { /* * Retrieve the first available USB request, protected by the * request lock. -- 2.42.0.758.gaed0368e0e-goog From nobody Wed Jan 7 03:59:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ABB5BCDB465 for ; Thu, 12 Oct 2023 00:24:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376551AbjJLAY6 (ORCPT ); Wed, 11 Oct 2023 20:24:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40640 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231381AbjJLAY4 (ORCPT ); Wed, 11 Oct 2023 20:24:56 -0400 Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F58B94 for ; Wed, 11 Oct 2023 17:24:55 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id d9443c01a7336-1c9d140fb3eso3484595ad.3 for ; Wed, 11 Oct 2023 17:24:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1697070295; x=1697675095; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=TG++fvWfitw/Sd3Hpgv4FLh87i4JPu5cxo2T/O4RJwY=; b=IQ7LCc4dLlKSkhl/k/jDiI6c6qxEapg6q03XfT+vMZt/x6+16yOiUq4zLS8KnCRBEd s3beUpzLqnK3yJ6QavMqqgcsL6GbjizRR6HdI9Af32TX26zaTkAPDi4WeFNOkNxVTkME 2FyvtiLucNPxALbvDGfQSW4cpIIi6cQNXKvbyNOP//qbeDB9LL2BkVGHjuwBwClHXj7U Aa637zUHDVlepYSQH4bfiwxw5CrNnKeImblV621OlWgvJciTJDnfKOBv3Pp2b3IKAm4v NvZYsQTouwY4LkppeCC8nJ1bsOWhaaaZDPJrHw911uBRGrmQN9vJeMQ3ZyR59mYqRuJH 04IQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697070295; x=1697675095; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TG++fvWfitw/Sd3Hpgv4FLh87i4JPu5cxo2T/O4RJwY=; b=SqaerRqrBkUw5ATmVN0fUtkaQEzMfhnQAg6hQBT4ABq9y2LchhcfBdtbsFrR4c6QBa 7LfwKW+LgPNcoRZcHAEWYy2kHX6UqPZSbs0AmSoEjD7QCS7OQjt3F2npcTolA3oqtjB4 MrIaQ6bkjizeNAE+GFSYVJDHHZ+nY1p3EHm4xpfFR8UpT2KZEJXYkdsR+iMye3Xj5bRv hfRO8AVf8eK47dC78IFGVrliqREZE5FRWeBRL0D0BbXJ9I/vGzWK0SVTKJ4h04v9w1oZ mXZfG44yWJvjvmmL3o0X0I1/iNR5PElC2V4feFLXBYvxJYXXyFk12aSKugMyNc8EkkZu lNTA== X-Gm-Message-State: AOJu0YyGj0VH/93ARmPK/5jEm9fkg1T1SHH2Sl91BBWvdWuEln6dm4rH jmuIqPDxr8M/Uz1cl7gbvHSQ0Tiysjws X-Google-Smtp-Source: AGHT+IExEy4MT1RlmnzZMLhm7/rDozk7wpxsAHnJrA5Qq1I4GYy529PiD6cmwEWrK8tPiRiz9sjCDjHq9E9y X-Received: from hi-h2o-specialist.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:3cef]) (user=arakesh job=sendgmr) by 2002:a17:90b:2391:b0:27d:1cfb:7185 with SMTP id mr17-20020a17090b239100b0027d1cfb7185mr21475pjb.9.1697070294985; Wed, 11 Oct 2023 17:24:54 -0700 (PDT) Date: Wed, 11 Oct 2023 17:24:49 -0700 In-Reply-To: <20230930184821.310143-1-arakesh@google.com> Mime-Version: 1.0 References: <20230930184821.310143-1-arakesh@google.com> X-Mailer: git-send-email 2.42.0.609.gbb76f46606-goog Message-ID: <20231012002451.254737-1-arakesh@google.com> Subject: [PATCH v4 1/3] usb: gadget: uvc: prevent use of disabled endpoint From: Avichal Rakesh To: arakesh@google.com, dan.scally@ideasonboard.com, laurent.pinchart@ideasonboard.com, m.grzeschik@pengutronix.de Cc: etalvala@google.com, gregkh@linuxfoundation.org, jchowdhary@google.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently the set_alt callback immediately disables the endpoint and queues the v4l2 streamoff event. However, as the streamoff event is processed asynchronously, it is possible that the video_pump thread attempts to queue requests to an already disabled endpoint. This change moves disabling usb endpoint to the end of streamoff event callback. As the endpoint's state can no longer be used, video_pump is now guarded by uvc->state as well. To be consistent with the actual streaming state, uvc->state is now toggled between CONNECTED and STREAMING from the v4l2 event callback only. Link: https://lore.kernel.org/20230615171558.GK741@pendragon.ideasonboard.c= om/ Link: https://lore.kernel.org/20230531085544.253363-1-dan.scally@ideasonboa= rd.com/ Reviewed-by: Michael Grzeschik Signed-off-by: Avichal Rakesh --- v1 -> v2: Rebased to ToT and reworded commit message. v2 -> v3: Fix email threading goof-up v3 -> v4: Address review comments & re-rebase to ToT drivers/usb/gadget/function/f_uvc.c | 11 +++++------ drivers/usb/gadget/function/f_uvc.h | 2 +- drivers/usb/gadget/function/uvc.h | 2 +- drivers/usb/gadget/function/uvc_v4l2.c | 21 ++++++++++++++++++--- drivers/usb/gadget/function/uvc_video.c | 3 ++- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/funct= ion/f_uvc.c index faa398109431..ae08341961eb 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -263,10 +263,13 @@ uvc_function_setup(struct usb_function *f, const stru= ct usb_ctrlrequest *ctrl) return 0; } -void uvc_function_setup_continue(struct uvc_device *uvc) +void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep) { struct usb_composite_dev *cdev =3D uvc->func.config->cdev; + if (disable_ep && uvc->video.ep) + usb_ep_disable(uvc->video.ep); + usb_composite_setup_continue(cdev); } @@ -337,15 +340,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned= interface, unsigned alt) if (uvc->state !=3D UVC_STATE_STREAMING) return 0; - if (uvc->video.ep) - usb_ep_disable(uvc->video.ep); - memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type =3D UVC_EVENT_STREAMOFF; v4l2_event_queue(&uvc->vdev, &v4l2_event); - uvc->state =3D UVC_STATE_CONNECTED; - return 0; + return USB_GADGET_DELAYED_STATUS; case 1: if (uvc->state !=3D UVC_STATE_CONNECTED) diff --git a/drivers/usb/gadget/function/f_uvc.h b/drivers/usb/gadget/funct= ion/f_uvc.h index 1db972d4beeb..e7f9f13f14dc 100644 --- a/drivers/usb/gadget/function/f_uvc.h +++ b/drivers/usb/gadget/function/f_uvc.h @@ -11,7 +11,7 @@ struct uvc_device; -void uvc_function_setup_continue(struct uvc_device *uvc); +void uvc_function_setup_continue(struct uvc_device *uvc, int disale_ep); void uvc_function_connect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/functio= n/uvc.h index 6751de8b63ad..989bc6b4e93d 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -177,7 +177,7 @@ struct uvc_file_handle { * Functions */ -extern void uvc_function_setup_continue(struct uvc_device *uvc); +extern void uvc_function_setup_continue(struct uvc_device *uvc, int disabl= e_ep); extern void uvc_function_connect(struct uvc_device *uvc); extern void uvc_function_disconnect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/fu= nction/uvc_v4l2.c index 3f0a9795c0d4..c0d77564a204 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -451,7 +451,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l= 2_buf_type type) * Complete the alternate setting selection setup phase now that * userspace is ready to provide video frames. */ - uvc_function_setup_continue(uvc); + uvc_function_setup_continue(uvc, 0); uvc->state =3D UVC_STATE_STREAMING; return 0; @@ -463,11 +463,19 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum = v4l2_buf_type type) struct video_device *vdev =3D video_devdata(file); struct uvc_device *uvc =3D video_get_drvdata(vdev); struct uvc_video *video =3D &uvc->video; + int ret =3D 0; if (type !=3D video->queue.queue.type) return -EINVAL; - return uvcg_video_enable(video, 0); + uvc->state =3D UVC_STATE_CONNECTED; + ret =3D uvcg_video_enable(video, 0); + if (ret < 0) { + return ret; + } + + uvc_function_setup_continue(uvc, 1); + return 0; } static int @@ -500,6 +508,14 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh, static void uvc_v4l2_disable(struct uvc_device *uvc) { uvc_function_disconnect(uvc); + /* + * Drop uvc->state to CONNECTED if it was streaming before. + * This ensures that the usb_requests are no longer queued + * to the controller. + */ + if (uvc->state =3D=3D UVC_STATE_STREAMING) + uvc->state =3D UVC_STATE_CONNECTED; + uvcg_video_enable(&uvc->video, 0); uvcg_free_buffers(&uvc->video.queue); uvc->func_connected =3D false; @@ -647,4 +663,3 @@ const struct v4l2_file_operations uvc_v4l2_fops =3D { .get_unmapped_area =3D uvcg_v4l2_get_unmapped_area, #endif }; - diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/f= unction/uvc_video.c index 91af3b1ef0d4..c334802ac0a4 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -384,13 +384,14 @@ static void uvcg_video_pump(struct work_struct *work) struct uvc_video_queue *queue =3D &video->queue; /* video->max_payload_size is only set when using bulk transfer */ bool is_bulk =3D video->max_payload_size; + struct uvc_device *uvc =3D video->uvc; struct usb_request *req =3D NULL; struct uvc_buffer *buf; unsigned long flags; bool buf_done; int ret; - while (video->ep->enabled) { + while (uvc->state =3D=3D UVC_STATE_STREAMING && video->ep->enabled) { /* * Retrieve the first available USB request, protected by the * request lock. -- 2.42.0.609.gbb76f46606-goog From nobody Wed Jan 7 03:59:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 514ECE92725 for ; Thu, 5 Oct 2023 18:09:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229756AbjJESJJ (ORCPT ); Thu, 5 Oct 2023 14:09:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51422 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230203AbjJESI1 (ORCPT ); Thu, 5 Oct 2023 14:08:27 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 04465112 for ; Thu, 5 Oct 2023 11:08:19 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-59f53027158so17128027b3.0 for ; Thu, 05 Oct 2023 11:08:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1696529298; x=1697134098; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=cGPEr42+ZwCTP+CEzEnFhGGfenBhCq6NKh2BAUdeTck=; b=1UAjV89+aPiZ6PfduyoOx/FVGFc1vjlm+88m960GJqSnjXrtwwqMI/qL9rcKTal9Ub YIqcddmQ0iGpp62XKF8UMBXnaUPqhfb8S26Tl+GctNI2A6S/6pLse//oqYHj7ArjLtG7 cSWvr1cPkExnnrBrBZ/H6a2hQm7RnRmg+2w6iSMNOCfkLl3uGuoWnakFuRmFfpCbRJsJ rGu5SJX9mBB4oU4EunUppIJO+Jb4Z80VaEZ+YX4b11S5Q9eqRMxFQ2u8T3SZKBacjDFT FE6huwNN5AFa7B4v8BhQBOwf9DT6jrhbu2NoyZCOcR1OK7Ce0cVArtbGlcX9GY8tVA0B rUDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696529298; x=1697134098; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=cGPEr42+ZwCTP+CEzEnFhGGfenBhCq6NKh2BAUdeTck=; b=TSzg2jQYbuRak7km3UDj39aLu8uPNz3ytSBOON+iHJbK0p55+GkbKWW9uqCQ749N3k J+E1myE1bgxr4l0vmjsv2VJG9lVR68BqJqefd1Ut5iPGa4HpgF0ucFnCSo/PMw9iIIda eh7lF2SgdnG1rRY9V6FRM6D8keahoEPbMH4Q6dUejPQX+EsYCc7ujqYVhoh2ArC68Vop 12W5lot0nL6tG+sdw2qRvNCa3/3/CRB8OWnYSVz5h/R4Htk5cuNwPcN/MGHnLT1SMWfA dfKtYB4Fj4MZuZYqlbm0u4jfBE2EH/lct8SnTW9m5B9Sh5lJd0TF9UbEQdTQ3K7d8HPd 8jHA== X-Gm-Message-State: AOJu0YwjpM37cOCXUSbJy1mQfMVevAzNNDBwcSsQVsk0usLrtSLMV1kK amr5AFwjNT7Gumi/YUMIuGyB+8qyYM4y X-Google-Smtp-Source: AGHT+IGohbK75EVXkfCZDbTpCYdI4cTufrVSsHUE2OXMHhyT7A/XkqzRLLmcg1lhHIXwLzwe32LvY3mmUFFy X-Received: from hi-h2o-specialist.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:3cef]) (user=arakesh job=sendgmr) by 2002:a5b:5c9:0:b0:d8b:737f:8240 with SMTP id w9-20020a5b05c9000000b00d8b737f8240mr103527ybp.0.1696529298114; Thu, 05 Oct 2023 11:08:18 -0700 (PDT) Date: Thu, 5 Oct 2023 11:08:12 -0700 In-Reply-To: <20230930184821.310143-1-arakesh@google.com> Mime-Version: 1.0 References: <20230930184821.310143-1-arakesh@google.com> X-Mailer: git-send-email 2.42.0.609.gbb76f46606-goog Message-ID: <20231005180814.3278050-1-arakesh@google.com> Subject: [PATCH v3 1/3] usb: gadget: uvc: prevent use of disabled endpoint From: Avichal Rakesh To: arakesh@google.com, dan.scally@ideasonboard.com, gregkh@linuxfoundation.org, laurent.pinchart@ideasonboard.com, m.grzeschik@pengutronix.de Cc: etalvala@google.com, jchowdhary@google.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently the set_alt callback immediately disables the endpoint and queues the v4l2 streamoff event. However, as the streamoff event is processed asynchronously, it is possible that the video_pump thread attempts to queue requests to an already disabled endpoint. This change moves disabling usb endpoint to the end of streamoff event callback. To be consistent with the actual streaming state, uvc->state is now toggled between CONNECTED and STREAMING from the v4l2 event callback only. Link: https://lore.kernel.org/20230615171558.GK741@pendragon.ideasonboard.c= om/ Link: https://lore.kernel.org/20230531085544.253363-1-dan.scally@ideasonboa= rd.com/ Signed-off-by: Avichal Rakesh Reviewed-by: --- v1 -> v2: Rebased to ToT and reworded commit message. v2 -> v3: Fix email threading goof-up drivers/usb/gadget/function/f_uvc.c | 11 +++++------ drivers/usb/gadget/function/f_uvc.h | 2 +- drivers/usb/gadget/function/uvc.h | 2 +- drivers/usb/gadget/function/uvc_v4l2.c | 21 ++++++++++++++++++--- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/funct= ion/f_uvc.c index faa398109431..75c9f9a3f884 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -263,10 +263,13 @@ uvc_function_setup(struct usb_function *f, const stru= ct usb_ctrlrequest *ctrl) return 0; } -void uvc_function_setup_continue(struct uvc_device *uvc) +void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep) { struct usb_composite_dev *cdev =3D uvc->func.config->cdev; + if (disable_ep && uvc->video.ep) { + usb_ep_disable(uvc->video.ep); + } usb_composite_setup_continue(cdev); } @@ -337,15 +340,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned= interface, unsigned alt) if (uvc->state !=3D UVC_STATE_STREAMING) return 0; - if (uvc->video.ep) - usb_ep_disable(uvc->video.ep); - memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type =3D UVC_EVENT_STREAMOFF; v4l2_event_queue(&uvc->vdev, &v4l2_event); - uvc->state =3D UVC_STATE_CONNECTED; - return 0; + return USB_GADGET_DELAYED_STATUS; case 1: if (uvc->state !=3D UVC_STATE_CONNECTED) diff --git a/drivers/usb/gadget/function/f_uvc.h b/drivers/usb/gadget/funct= ion/f_uvc.h index 1db972d4beeb..e7f9f13f14dc 100644 --- a/drivers/usb/gadget/function/f_uvc.h +++ b/drivers/usb/gadget/function/f_uvc.h @@ -11,7 +11,7 @@ struct uvc_device; -void uvc_function_setup_continue(struct uvc_device *uvc); +void uvc_function_setup_continue(struct uvc_device *uvc, int disale_ep); void uvc_function_connect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/functio= n/uvc.h index 6751de8b63ad..989bc6b4e93d 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -177,7 +177,7 @@ struct uvc_file_handle { * Functions */ -extern void uvc_function_setup_continue(struct uvc_device *uvc); +extern void uvc_function_setup_continue(struct uvc_device *uvc, int disabl= e_ep); extern void uvc_function_connect(struct uvc_device *uvc); extern void uvc_function_disconnect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/fu= nction/uvc_v4l2.c index 3f0a9795c0d4..3d3469883ed0 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -451,7 +451,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l= 2_buf_type type) * Complete the alternate setting selection setup phase now that * userspace is ready to provide video frames. */ - uvc_function_setup_continue(uvc); + uvc_function_setup_continue(uvc, 0); uvc->state =3D UVC_STATE_STREAMING; return 0; @@ -463,11 +463,19 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum = v4l2_buf_type type) struct video_device *vdev =3D video_devdata(file); struct uvc_device *uvc =3D video_get_drvdata(vdev); struct uvc_video *video =3D &uvc->video; + int ret =3D 0; if (type !=3D video->queue.queue.type) return -EINVAL; - return uvcg_video_enable(video, 0); + uvc->state =3D UVC_STATE_CONNECTED; + ret =3D uvcg_video_enable(video, 0); + if (ret < 0) { + return ret; + } + + uvc_function_setup_continue(uvc, 1); + return 0; } static int @@ -500,6 +508,14 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh, static void uvc_v4l2_disable(struct uvc_device *uvc) { uvc_function_disconnect(uvc); + if (uvc->state =3D=3D UVC_STATE_STREAMING) { + /* + * Drop uvc->state to CONNECTED if it was streaming before. + * This ensures that the usb_requests are no longer queued + * to the controller. + */ + uvc->state =3D UVC_STATE_CONNECTED; + } uvcg_video_enable(&uvc->video, 0); uvcg_free_buffers(&uvc->video.queue); uvc->func_connected =3D false; @@ -647,4 +663,3 @@ const struct v4l2_file_operations uvc_v4l2_fops =3D { .get_unmapped_area =3D uvcg_v4l2_get_unmapped_area, #endif }; - -- 2.42.0.609.gbb76f46606-goog From nobody Wed Jan 7 03:59:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7B000E728E1 for ; Sat, 30 Sep 2023 18:48:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234737AbjI3Ssg (ORCPT ); Sat, 30 Sep 2023 14:48:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234734AbjI3Sse (ORCPT ); Sat, 30 Sep 2023 14:48:34 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D19A9E3 for ; Sat, 30 Sep 2023 11:48:31 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-d81c39acfd9so22170164276.0 for ; Sat, 30 Sep 2023 11:48:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1696099711; x=1696704511; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=yVUNhv8Ca4Bneo2huWLmhKm4bUNhRAbGx7sDL56KZmE=; b=dn3jzL6UBvfdgT9ODHHBwGjuRi5jo/Qg9SAmRMCPoND7jdzfrDXUxpBRezyUyO1OGI pkPxAWPoiNYTz4t+mFpUvxLz245ILtM3OdO6r8HBAkA1zuYmJBHuS+DrXJUC6jPh/CcJ LuiEI3eQMvq1DvQtTvpIxAByi2LuAqHG5yiDf8MHGrWAaRMksEnEvn5GbEsq8jh8hDNf ffc6w0ZSBEGoKXUNF3NdQ1YlVzCDDWJlC8kuFhtiBd9CWIwjXq1mXPzdSZ6kojZJTaWU PvUI9V53D1qfcG2bHodz3kjKsUSOcark9mvPOpUSU28tO3THWnEkqlCpaQMTaWHeXnyM buvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696099711; x=1696704511; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=yVUNhv8Ca4Bneo2huWLmhKm4bUNhRAbGx7sDL56KZmE=; b=A7KlTmpkQfxCW1blL765EF4kHQeB+mkgmigeNXtxQn18BnPX0UHiblTpFlVjzZTMDT G4jPp2jy9MFRzEmI2QinGzSvhVy+EtRQO+cxl+IAiO3D5S3d0A7wTScvIeat1G+72NlE sYfYb7qHki8nJFtfUq30OK35XTp73/zPIGepeDwU3hY+S79zorPQIxqAsbjDGXBI1zbQ Th5YQEQKHtXYBwjdPhC36QxcK+b8Iq/wQJRPYrCGhQ3NgbhZKCMWMS3aegti8HWe1pL7 RaYLvH3wCrj4yGh2Vgu9DhYSlvFWaWJmo5TG5inKcZTftc3Ji+Trm1npPE51aJiWLllE ebzg== X-Gm-Message-State: AOJu0YxX3e6JrxH8yy/D4titjBFQSbKnWL22KlQKvd8mSwpeiyhv4Xem zXwRcsv/BPyMh2gzJ7MBY7sRgtpe22GN X-Google-Smtp-Source: AGHT+IH2JL4Oo3hXmwpi/7cv9ZKyYjENj1pnLNMUL0gqAEOjFbEGxjST1e6xqKTlnkxrjBsDeJB818mCYTdt X-Received: from hi-h2o-specialist.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:3cef]) (user=arakesh job=sendgmr) by 2002:a25:6f82:0:b0:d81:43c7:61ed with SMTP id k124-20020a256f82000000b00d8143c761edmr121329ybc.5.1696099711011; Sat, 30 Sep 2023 11:48:31 -0700 (PDT) Date: Sat, 30 Sep 2023 11:48:19 -0700 In-Reply-To: <20230930184821.310143-1-arakesh@google.com> Mime-Version: 1.0 References: <20230930184821.310143-1-arakesh@google.com> X-Mailer: git-send-email 2.42.0.582.g8ccd20d70d-goog Message-ID: <20230930184821.310143-2-arakesh@google.com> Subject: [PATCH v1 1/3] usb: gadget: uvc: prevent use of disabled endpoint From: Avichal Rakesh To: Laurent Pinchart , Daniel Scally , Greg Kroah-Hartman , Michael Grzeschik Cc: jchowdhary@google.com, etalvala@google.com, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Avichal Rakesh Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently the set_alt callback immediately disables the endpoint and queues the v4l2 streamoff event. However, as the streamoff event is processed asynchronously, it is possible that the video_pump thread attempts to queue requests to an already disabled endpoint. This change moves disabling usb endpoint to the end of streamoff event callback. As the endpoint's state can no longer be used, video_pump is now guarded by uvc->state as well. To be consistent with the actual streaming state, uvc->state is now toggled between CONNECTED and STREAMING from the v4l2 event callback only. Link: https://lore.kernel.org/20230615171558.GK741@pendragon.ideasonboard.c= om/ Link: https://lore.kernel.org/20230531085544.253363-1-dan.scally@ideasonboa= rd.com/ Signed-off-by: Avichal Rakesh --- drivers/usb/gadget/function/f_uvc.c | 11 +++++------ drivers/usb/gadget/function/f_uvc.h | 2 +- drivers/usb/gadget/function/uvc.h | 2 +- drivers/usb/gadget/function/uvc_v4l2.c | 21 ++++++++++++++++++--- drivers/usb/gadget/function/uvc_video.c | 3 ++- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/funct= ion/f_uvc.c index faa398109431..75c9f9a3f884 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -263,10 +263,13 @@ uvc_function_setup(struct usb_function *f, const stru= ct usb_ctrlrequest *ctrl) return 0; } =20 -void uvc_function_setup_continue(struct uvc_device *uvc) +void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep) { struct usb_composite_dev *cdev =3D uvc->func.config->cdev; =20 + if (disable_ep && uvc->video.ep) { + usb_ep_disable(uvc->video.ep); + } usb_composite_setup_continue(cdev); } =20 @@ -337,15 +340,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned= interface, unsigned alt) if (uvc->state !=3D UVC_STATE_STREAMING) return 0; =20 - if (uvc->video.ep) - usb_ep_disable(uvc->video.ep); - memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type =3D UVC_EVENT_STREAMOFF; v4l2_event_queue(&uvc->vdev, &v4l2_event); =20 - uvc->state =3D UVC_STATE_CONNECTED; - return 0; + return USB_GADGET_DELAYED_STATUS; =20 case 1: if (uvc->state !=3D UVC_STATE_CONNECTED) diff --git a/drivers/usb/gadget/function/f_uvc.h b/drivers/usb/gadget/funct= ion/f_uvc.h index 1db972d4beeb..e7f9f13f14dc 100644 --- a/drivers/usb/gadget/function/f_uvc.h +++ b/drivers/usb/gadget/function/f_uvc.h @@ -11,7 +11,7 @@ =20 struct uvc_device; =20 -void uvc_function_setup_continue(struct uvc_device *uvc); +void uvc_function_setup_continue(struct uvc_device *uvc, int disale_ep); =20 void uvc_function_connect(struct uvc_device *uvc); =20 diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/functio= n/uvc.h index 6751de8b63ad..989bc6b4e93d 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -177,7 +177,7 @@ struct uvc_file_handle { * Functions */ =20 -extern void uvc_function_setup_continue(struct uvc_device *uvc); +extern void uvc_function_setup_continue(struct uvc_device *uvc, int disabl= e_ep); extern void uvc_function_connect(struct uvc_device *uvc); extern void uvc_function_disconnect(struct uvc_device *uvc); =20 diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/fu= nction/uvc_v4l2.c index 3f0a9795c0d4..3d3469883ed0 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -451,7 +451,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l= 2_buf_type type) * Complete the alternate setting selection setup phase now that * userspace is ready to provide video frames. */ - uvc_function_setup_continue(uvc); + uvc_function_setup_continue(uvc, 0); uvc->state =3D UVC_STATE_STREAMING; =20 return 0; @@ -463,11 +463,19 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum = v4l2_buf_type type) struct video_device *vdev =3D video_devdata(file); struct uvc_device *uvc =3D video_get_drvdata(vdev); struct uvc_video *video =3D &uvc->video; + int ret =3D 0; =20 if (type !=3D video->queue.queue.type) return -EINVAL; =20 - return uvcg_video_enable(video, 0); + uvc->state =3D UVC_STATE_CONNECTED; + ret =3D uvcg_video_enable(video, 0); + if (ret < 0) { + return ret; + } + + uvc_function_setup_continue(uvc, 1); + return 0; } =20 static int @@ -500,6 +508,14 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh, static void uvc_v4l2_disable(struct uvc_device *uvc) { uvc_function_disconnect(uvc); + if (uvc->state =3D=3D UVC_STATE_STREAMING) { + /* + * Drop uvc->state to CONNECTED if it was streaming before. + * This ensures that the usb_requests are no longer queued + * to the controller. + */ + uvc->state =3D UVC_STATE_CONNECTED; + } uvcg_video_enable(&uvc->video, 0); uvcg_free_buffers(&uvc->video.queue); uvc->func_connected =3D false; @@ -647,4 +663,3 @@ const struct v4l2_file_operations uvc_v4l2_fops =3D { .get_unmapped_area =3D uvcg_v4l2_get_unmapped_area, #endif }; - diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/f= unction/uvc_video.c index 91af3b1ef0d4..70ff88854539 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -382,6 +382,7 @@ static void uvcg_video_pump(struct work_struct *work) { struct uvc_video *video =3D container_of(work, struct uvc_video, pump); struct uvc_video_queue *queue =3D &video->queue; + struct uvc_device *uvc =3D video->uvc; /* video->max_payload_size is only set when using bulk transfer */ bool is_bulk =3D video->max_payload_size; struct usb_request *req =3D NULL; @@ -390,7 +391,7 @@ static void uvcg_video_pump(struct work_struct *work) bool buf_done; int ret; =20 - while (video->ep->enabled) { + while (uvc->state =3D=3D UVC_STATE_STREAMING && video->ep->enabled) { /* * Retrieve the first available USB request, protected by the * request lock. --=20 2.42.0.582.g8ccd20d70d-goog From nobody Wed Jan 7 03:59:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8A374E71D55 for ; Sat, 30 Sep 2023 18:48:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234745AbjI3Ssj (ORCPT ); Sat, 30 Sep 2023 14:48:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55048 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234734AbjI3Ssh (ORCPT ); Sat, 30 Sep 2023 14:48:37 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 070AAD3 for ; Sat, 30 Sep 2023 11:48:35 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id 41be03b00d2f7-5803b6fadceso11936399a12.0 for ; Sat, 30 Sep 2023 11:48:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1696099714; x=1696704514; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=mAs460jPiMP8R4cGJH03uN3F+PMNEKWmOscua1DAK48=; b=Y6pweDJp4Qn1rPKAL66slcaJGYTwDBvuqU9PMwSH+hgkZuVHqyrDsa/ur0RQyQe/O8 D7kG8M8FpIbYe2crnJpN9V3HOmZzZFaC4s6J/g/ORjGG3F/Sfubj40snFA0UEzZyRWWN 8nYgmhTsnj6HO4r6dgzeLEoBW0pJ3g0mUJwdNaWIu6tW/M55fDjNqbNPog73ReSbD/AP 3oXvUtCVEppxjw2CENX4huGGDrNT39nUU0QtPuraEEFKzLx4h7IE0RQyKhy7a3PBK2ha plmLTLoVaqCYMh7ouUq+nyjYnHKyjriJQIw6fYCwsbIlJdDakLmSNjMjK5qVLUyGmTMO 553g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696099714; x=1696704514; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mAs460jPiMP8R4cGJH03uN3F+PMNEKWmOscua1DAK48=; b=M//TJdlyo0Bjeix1Leosx0VYx3NNKwl8I2E6PEMbPCeF1noase+IxZn2xr2iHFb7YT wljjAzH4PaY9Tzrf+W4jAxIKD2G4TLzwOmZNvq2zicjgnL8WIvrX3gos67PZ4783FHxw 4OWbBsbVhd8EZ2TUkIxYNGuKwvuxDPO6MFL8IxrStKTDmu28Q1g5dKSCbE4xhzRgRqnc XUX8DhsqTRjnHqZ76KBYd4CmXj3sTR5FwEPtH7Z4YtxqyfhskLGq0lD5Hsn+dzoCP9Vb q75/zkV2ki/PkdWC12gLYSBipMsXMk0EdMteXsSdo0aiVDM8VKUu+zvl6MiWrqZmY43B P5PQ== X-Gm-Message-State: AOJu0Yzo115DT3kcwcYFQlqk6jUgaoW2NxnzlV2YlaLvTTdYyRfzJRlZ Jbgmf+QM1Fd0mgKRuafAfGWSHnpJhxmo X-Google-Smtp-Source: AGHT+IGmIf/Hih00Q1XGFIl1z5z8HHKIzTAAmlYv2pxIx8tAIAj4qLz8C06N20kEcWtkUip+2fmYUhZsDkON X-Received: from hi-h2o-specialist.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:3cef]) (user=arakesh job=sendgmr) by 2002:a63:3649:0:b0:56f:8ff0:d164 with SMTP id d70-20020a633649000000b0056f8ff0d164mr114801pga.2.1696099714278; Sat, 30 Sep 2023 11:48:34 -0700 (PDT) Date: Sat, 30 Sep 2023 11:48:20 -0700 In-Reply-To: <20230930184821.310143-1-arakesh@google.com> Mime-Version: 1.0 References: <20230930184821.310143-1-arakesh@google.com> X-Mailer: git-send-email 2.42.0.582.g8ccd20d70d-goog Message-ID: <20230930184821.310143-3-arakesh@google.com> Subject: [PATCH v1 2/3] usb: gadget: uvc: Allocate uvc_requests one at a time From: Avichal Rakesh To: Laurent Pinchart , Daniel Scally , Greg Kroah-Hartman , Michael Grzeschik Cc: jchowdhary@google.com, etalvala@google.com, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Avichal Rakesh , Michael Grzeschik Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, the uvc gadget driver allocates all uvc_requests as one array and deallocates them all when the video stream stops. This includes de-allocating all the usb_requests associated with those uvc_requests. This can lead to use-after-free issues if any of those de-allocated usb_requests were still owned by the usb controller. This patch is 1 of 2 patches addressing the use-after-free issue. Instead of bulk allocating all uvc_requests as an array, this patch allocates uvc_requests one at a time, which should allows for similar granularity when deallocating the uvc_requests. This patch has no functional changes other than allocating each uvc_request separately, and similarly freeing each of them separately. Link: https://lore.kernel.org/7cd81649-2795-45b6-8c10-b7df1055020d@google.c= om Suggested-by: Michael Grzeschik Signed-off-by: Avichal Rakesh --- drivers/usb/gadget/function/uvc.h | 3 +- drivers/usb/gadget/function/uvc_video.c | 90 ++++++++++++++----------- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/functio= n/uvc.h index 989bc6b4e93d..993694da0bbc 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -81,6 +81,7 @@ struct uvc_request { struct sg_table sgt; u8 header[UVCG_REQUEST_HEADER_LEN]; struct uvc_buffer *last_buf; + struct list_head list; }; =20 struct uvc_video { @@ -102,7 +103,7 @@ struct uvc_video { =20 /* Requests */ unsigned int req_size; - struct uvc_request *ureq; + struct list_head ureqs; /* all uvc_requests allocated by uvc_video */ struct list_head req_free; spinlock_t req_lock; =20 diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/f= unction/uvc_video.c index 70ff88854539..ffecd7a140dc 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -227,6 +227,23 @@ uvc_video_encode_isoc(struct usb_request *req, struct = uvc_video *video, * Request handling */ =20 +static void uvc_video_free_request(struct uvc_request *ureq, struct usb_ep= *ep) +{ + sg_free_table(&ureq->sgt); + if (ureq->req && ep) { + usb_ep_free_request(ep, ureq->req); + ureq->req =3D NULL; + } + + kfree(ureq->req_buffer); + ureq->req_buffer =3D NULL; + + if (!list_empty(&ureq->list)) + list_del_init(&ureq->list); + + kfree(ureq); +} + static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request= *req) { int ret; @@ -293,27 +310,13 @@ uvc_video_complete(struct usb_ep *ep, struct usb_requ= est *req) static int uvc_video_free_requests(struct uvc_video *video) { - unsigned int i; - - if (video->ureq) { - for (i =3D 0; i < video->uvc_num_requests; ++i) { - sg_free_table(&video->ureq[i].sgt); - - if (video->ureq[i].req) { - usb_ep_free_request(video->ep, video->ureq[i].req); - video->ureq[i].req =3D NULL; - } + struct uvc_request *ureq, *temp; =20 - if (video->ureq[i].req_buffer) { - kfree(video->ureq[i].req_buffer); - video->ureq[i].req_buffer =3D NULL; - } - } - - kfree(video->ureq); - video->ureq =3D NULL; + list_for_each_entry_safe(ureq, temp, &video->ureqs, list) { + uvc_video_free_request(ureq, video->ep); } =20 + INIT_LIST_HEAD(&video->ureqs); INIT_LIST_HEAD(&video->req_free); video->req_size =3D 0; return 0; @@ -322,6 +325,7 @@ uvc_video_free_requests(struct uvc_video *video) static int uvc_video_alloc_requests(struct uvc_video *video) { + struct uvc_request *ureq; unsigned int req_size; unsigned int i; int ret =3D -ENOMEM; @@ -332,29 +336,31 @@ uvc_video_alloc_requests(struct uvc_video *video) * max_t(unsigned int, video->ep->maxburst, 1) * (video->ep->mult); =20 - video->ureq =3D kcalloc(video->uvc_num_requests, sizeof(struct uvc_reques= t), GFP_KERNEL); - if (video->ureq =3D=3D NULL) - return -ENOMEM; - - for (i =3D 0; i < video->uvc_num_requests; ++i) { - video->ureq[i].req_buffer =3D kmalloc(req_size, GFP_KERNEL); - if (video->ureq[i].req_buffer =3D=3D NULL) + INIT_LIST_HEAD(&video->ureqs); + for (i =3D 0; i < video->uvc_num_requests; i++) { + ureq =3D kzalloc(sizeof(struct uvc_request), GFP_KERNEL); + if (ureq =3D=3D NULL) goto error; + INIT_LIST_HEAD(&ureq->list); + list_add_tail(&ureq->list, &video->ureqs); + } =20 - video->ureq[i].req =3D usb_ep_alloc_request(video->ep, GFP_KERNEL); - if (video->ureq[i].req =3D=3D NULL) + list_for_each_entry(ureq, &video->ureqs, list) { + ureq->req_buffer =3D kmalloc(req_size, GFP_KERNEL); + if (ureq->req_buffer =3D=3D NULL) goto error; - - video->ureq[i].req->buf =3D video->ureq[i].req_buffer; - video->ureq[i].req->length =3D 0; - video->ureq[i].req->complete =3D uvc_video_complete; - video->ureq[i].req->context =3D &video->ureq[i]; - video->ureq[i].video =3D video; - video->ureq[i].last_buf =3D NULL; - - list_add_tail(&video->ureq[i].req->list, &video->req_free); + ureq->req =3D usb_ep_alloc_request(video->ep, GFP_KERNEL); + if (ureq->req =3D=3D NULL) + goto error; + ureq->req->buf =3D ureq->req_buffer; + ureq->req->length =3D 0; + ureq->req->complete =3D uvc_video_complete; + ureq->req->context =3D ureq; + ureq->video =3D video; + ureq->last_buf =3D NULL; + list_add_tail(&ureq->req->list, &video->req_free); /* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */ - sg_alloc_table(&video->ureq[i].sgt, + sg_alloc_table(&ureq->sgt, DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN, PAGE_SIZE) + 2, GFP_KERNEL); } @@ -489,8 +495,8 @@ static void uvcg_video_pump(struct work_struct *work) */ int uvcg_video_enable(struct uvc_video *video, int enable) { - unsigned int i; int ret; + struct uvc_request *ureq; =20 if (video->ep =3D=3D NULL) { uvcg_info(&video->uvc->func, @@ -502,9 +508,10 @@ int uvcg_video_enable(struct uvc_video *video, int ena= ble) cancel_work_sync(&video->pump); uvcg_queue_cancel(&video->queue, 0); =20 - for (i =3D 0; i < video->uvc_num_requests; ++i) - if (video->ureq && video->ureq[i].req) - usb_ep_dequeue(video->ep, video->ureq[i].req); + list_for_each_entry(ureq, &video->ureqs, list) { + if (ureq->req) + usb_ep_dequeue(video->ep, ureq->req); + } =20 uvc_video_free_requests(video); uvcg_queue_enable(&video->queue, 0); @@ -536,6 +543,7 @@ int uvcg_video_enable(struct uvc_video *video, int enab= le) */ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) { + INIT_LIST_HEAD(&video->ureqs); INIT_LIST_HEAD(&video->req_free); spin_lock_init(&video->req_lock); INIT_WORK(&video->pump, uvcg_video_pump); --=20 2.42.0.582.g8ccd20d70d-goog From nobody Wed Jan 7 03:59:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EAC79E71D55 for ; Sat, 30 Sep 2023 18:48:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234627AbjI3Ssp (ORCPT ); Sat, 30 Sep 2023 14:48:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55114 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234751AbjI3Ssn (ORCPT ); Sat, 30 Sep 2023 14:48:43 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 111C0100 for ; Sat, 30 Sep 2023 11:48:39 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-59f6902dc8bso215755367b3.0 for ; Sat, 30 Sep 2023 11:48:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1696099718; x=1696704518; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8sS0/uaQLhAvse+d/NY7S3JtHJHgQXnCXFHZHAD5jYQ=; b=tRLc6bqBTUC+HjWpMuM+lJSzMX7JOeSi+5VjDfx965ORJh4k2dXGYvpooRLZTa5g2f o/6cYNB6pXGXw+DCQoQXyCxfrGz8oQW6bkTbAxP1rlO7l1cQp4i8L+NZ/Yl8u4FhG+WB Bkb4S9gRWR04NGOJMishgCr4Jbzi3OF+ePmmajq+efN53iurJvUIUVT1v6D11kKRP8nY RZl/4CP6Qlxfk5ZmiiPAs4s1hi6nG4lOhJq3YuctxnKiMqhL50tNTmRpTp5SJFO/2bhL RsDbJXpNVrmCElhY2PHGbGaP9tjPTVxBzJze0umhW8G+/omiQnNzZriw4XqCNxP1ybJW 2vmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696099718; x=1696704518; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8sS0/uaQLhAvse+d/NY7S3JtHJHgQXnCXFHZHAD5jYQ=; b=fYwe6FwzyAylKg7gydbZwJF3hQIhmG92G4kc2lCdX7eXBosMPg9+bbVg5yX1vL+Muk xAubc/X2vb2bJKy2olmRUg1X1bwCTGCwLM2x1PVrMJwdRA/C/OmLVgZ8jUigBmzuD0jz WRdM2EZW1hwnJ0ATUpU9C2M5i23yiC4dQiw8Xs7KFl+d0Va3W+10YGkpCedt2JbxWMla bg9B6ExZC2Ag5hJkHI3ioREHyY2wHg10j9UvC2Di0B4y32SfxEoJEzuB5K2Uraie6f2i OAYiJbFtnsxSiPa4tv7EX+SVGuzhpW21ZUttB/ZzexEoCMGFYXvyfHimDnPsO3kMD9HH 4CHw== X-Gm-Message-State: AOJu0Yz8PI3jsyUn2qLbtwGEOBikT8GrpWDHRqD9cfQuZkJoo3XQO9mV fNZ/WEw53gHikYVhoEt6rpuAjO/AdZKp X-Google-Smtp-Source: AGHT+IHWdhL5RAVxsyWTiI4/e6dqT9qBN4mYpBbtKdY2IFEu9Ctuxp7yzyHR+CXeMVVBwlqF+9X+xO7MZ7h0 X-Received: from hi-h2o-specialist.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:3cef]) (user=arakesh job=sendgmr) by 2002:a05:690c:3412:b0:579:f832:74b with SMTP id fn18-20020a05690c341200b00579f832074bmr130768ywb.10.1696099718241; Sat, 30 Sep 2023 11:48:38 -0700 (PDT) Date: Sat, 30 Sep 2023 11:48:21 -0700 In-Reply-To: <20230930184821.310143-1-arakesh@google.com> Mime-Version: 1.0 References: <20230930184821.310143-1-arakesh@google.com> X-Mailer: git-send-email 2.42.0.582.g8ccd20d70d-goog Message-ID: <20230930184821.310143-4-arakesh@google.com> Subject: [PATCH v1 3/3] usb: gadget: uvc: Fix use-after-free for inflight usb_requests From: Avichal Rakesh To: Laurent Pinchart , Daniel Scally , Greg Kroah-Hartman , Michael Grzeschik Cc: jchowdhary@google.com, etalvala@google.com, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Avichal Rakesh , Michael Grzeschik Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, the uvc gadget driver allocates all uvc_requests as one array and deallocates them all when the video stream stops. This includes de-allocating all the usb_requests associated with those uvc_requests. This can lead to use-after-free issues if any of those de-allocated usb_requests were still owned by the usb controller. This is patch 2 of 2 in fixing the use-after-free issue. It adds a new flag to uvc_request to mark it as 'abandoned'. When disabling the video stream, instead of de-allocating all uvc_requests and usb_requests, the gadget driver only de-allocates those usb_requests that are currently owned by the gadget driver (as present in req_free). Other usb_requests have their corresponding 'is_abandoned' flag tripped, and the usb_requests complete handler takes care of freeing the usb_request and its corresponding uvc_request. This should ensure that uvc gadget driver never accidentally de-allocates a usb_request that it doesn't own. Link: https://lore.kernel.org/7cd81649-2795-45b6-8c10-b7df1055020d@google.c= om Suggested-by: Michael Grzeschik Signed-off-by: Avichal Rakesh --- drivers/usb/gadget/function/uvc.h | 1 + drivers/usb/gadget/function/uvc_video.c | 106 ++++++++++++++++++++---- 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/functio= n/uvc.h index 993694da0bbc..e69cfb7cced1 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -82,6 +82,7 @@ struct uvc_request { u8 header[UVCG_REQUEST_HEADER_LEN]; struct uvc_buffer *last_buf; struct list_head list; + bool is_abandoned; }; =20 struct uvc_video { diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/f= unction/uvc_video.c index ffecd7a140dc..aad7dcba46ee 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -271,7 +271,21 @@ uvc_video_complete(struct usb_ep *ep, struct usb_reque= st *req) struct uvc_video *video =3D ureq->video; struct uvc_video_queue *queue =3D &video->queue; struct uvc_device *uvc =3D video->uvc; + struct uvc_buffer *last_buf; unsigned long flags; + bool is_abandoned; + + spin_lock_irqsave(&video->req_lock, flags); + is_abandoned =3D ureq->is_abandoned; + last_buf =3D ureq->last_buf; + ureq->last_buf =3D NULL; + spin_unlock_irqrestore(&video->req_lock, flags); + + if (is_abandoned) { + uvcg_dbg(&video->uvc->func, "Freeing abandoned usb_request\n"); + uvc_video_free_request(ureq, ep); + return; + } =20 switch (req->status) { case 0: @@ -294,15 +308,29 @@ uvc_video_complete(struct usb_ep *ep, struct usb_requ= est *req) uvcg_queue_cancel(queue, 0); } =20 - if (ureq->last_buf) { - uvcg_complete_buffer(&video->queue, ureq->last_buf); - ureq->last_buf =3D NULL; + if (last_buf) { + spin_lock_irqsave(&video->queue.irqlock, flags); + uvcg_complete_buffer(&video->queue, last_buf); + spin_unlock_irqrestore(&video->queue.irqlock, flags); } =20 + /* + * request might have been abandoned while being processed. + * do a last minute check before queueing the request back. + */ spin_lock_irqsave(&video->req_lock, flags); - list_add_tail(&req->list, &video->req_free); + is_abandoned =3D ureq->is_abandoned; + if (!is_abandoned) + list_add_tail(&req->list, &video->req_free); spin_unlock_irqrestore(&video->req_lock, flags); =20 + if (is_abandoned) { + uvcg_dbg(&video->uvc->func, + "usb_request abandoned mid-processing - freeing.\n"); + uvc_video_free_request(ureq, ep); + return; + } + if (uvc->state =3D=3D UVC_STATE_STREAMING) queue_work(video->async_wq, &video->pump); } @@ -366,7 +394,6 @@ uvc_video_alloc_requests(struct uvc_video *video) } =20 video->req_size =3D req_size; - return 0; =20 error: @@ -490,13 +517,69 @@ static void uvcg_video_pump(struct work_struct *work) return; } =20 +/* + * Disable video stream. This ensures that any inflight usb requests are m= arked + * for clean up and all video buffers are dropped before returning. + */ +static void uvcg_video_disable(struct uvc_video *video) +{ + struct uvc_buffer *buf, *tmp_buf; + struct uvc_request *ureq, *temp; + struct list_head buf_list; /* track in-flight video buffers */ + struct usb_request *req; + unsigned long flags; + + cancel_work_sync(&video->pump); + uvcg_queue_cancel(&video->queue, 0); + + INIT_LIST_HEAD(&buf_list); + spin_lock_irqsave(&video->req_lock, flags); + /* abandon all usb requests */ + list_for_each_entry_safe(ureq, temp, &video->ureqs, list) { + ureq->is_abandoned =3D true; + if (ureq->last_buf) { + list_add(&ureq->last_buf->queue, &buf_list); + ureq->last_buf =3D NULL; + } + list_del_init(&ureq->list); + if (ureq->req) + usb_ep_dequeue(video->ep, ureq->req); + } + /* + * re-add uvc_requests currently owned by the gadget to + * video->ureqs to be deallocated + */ + list_for_each_entry(req, &video->req_free, list) { + ureq =3D req->context; + list_add_tail(&ureq->list, &video->ureqs); + } + spin_unlock_irqrestore(&video->req_lock, flags); + + /* + * drop abandoned uvc_buffers, as the completion handler + * no longer will + */ + if (!list_empty(&buf_list)) { + spin_lock_irqsave(&video->queue.irqlock, flags); + list_for_each_entry_safe(buf, tmp_buf, + &buf_list, queue) { + video->queue.flags |=3D UVC_QUEUE_DROP_INCOMPLETE; + uvcg_complete_buffer(&video->queue, buf); + list_del(&buf->queue); + } + spin_unlock_irqrestore(&video->queue.irqlock, flags); + } + + uvc_video_free_requests(video); + uvcg_queue_enable(&video->queue, 0); +} + /* * Enable or disable the video stream. */ int uvcg_video_enable(struct uvc_video *video, int enable) { int ret; - struct uvc_request *ureq; =20 if (video->ep =3D=3D NULL) { uvcg_info(&video->uvc->func, @@ -505,16 +588,7 @@ int uvcg_video_enable(struct uvc_video *video, int ena= ble) } =20 if (!enable) { - cancel_work_sync(&video->pump); - uvcg_queue_cancel(&video->queue, 0); - - list_for_each_entry(ureq, &video->ureqs, list) { - if (ureq->req) - usb_ep_dequeue(video->ep, ureq->req); - } - - uvc_video_free_requests(video); - uvcg_queue_enable(&video->queue, 0); + uvcg_video_disable(video); return 0; } =20 --=20 2.42.0.582.g8ccd20d70d-goog