All of lore.kernel.org
 help / color / mirror / Atom feed
From: Felipe Balbi <balbi@kernel.org>
To: Baolin Wang <baolin.wang@linaro.org>
Cc: Greg KH <gregkh@linuxfoundation.org>,
	Mark Brown <broonie@kernel.org>, USB <linux-usb@vger.kernel.org>,
	LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] dwc3: gadget: Introduce dwc3_endpoint_xfer_xxx() to check endpoint type
Date: Thu, 26 May 2016 10:48:54 +0300	[thread overview]
Message-ID: <8760u1qmxl.fsf@linux.intel.com> (raw)
In-Reply-To: <CAMz4kuJti6uXY6988xu-CWOr7H5hhO_=juz84LQEqLG7uFwegQ@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5478 bytes --]


Hi,

Baolin Wang <baolin.wang@linaro.org> writes:
> Hi Felipe,
>
> On 26 May 2016 at 14:22, Felipe Balbi <balbi@kernel.org> wrote:
>>
>> Hi,
>>
>> Baolin Wang <baolin.wang@linaro.org> writes:
>>> When handling the endpoint interrupt handler, it maybe disable the endpoint
>>> from another core user to set the USB endpoint descriptor pointor to be NULL
>>> while issuing usb_gadget_giveback_request() function to release lock. So it
>>> will be one bug to check the endpoint type by usb_endpoint_xfer_xxx() APIs with
>>> one NULL USB endpoint descriptor.
>>
>> too complex, Baolin :-) Can you see if this helps:
>>
>> https://git.kernel.org/cgit/linux/kernel/git/balbi/usb.git/commit/?id=88bf752cfb55e57a78e27c931c9fef63240c739a
>>
>> The only situation when that can happen is while we drop our lock on
>> dwc3_gadget_giveback().
>
> OK, But line 1974 and line 2025 as below may be at risk? So I think
> can we have a common place to solve the problem in case
> usb_endpoint_xfer_xxx() APIs are issued at this risk? What do you
> think? Thanks.
>
> 1956 static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
> 1957                 const struct dwc3_event_depevt *event, int status)
> 1958 {
> 1959         struct dwc3_request     *req;
> 1960         struct dwc3_trb         *trb;
> 1961         unsigned int            slot;
> 1962         unsigned int            i;
> 1963         int                     ret;
> 1964
> 1965         do {
> 1966                 req = next_request(&dep->req_queued);
> 1967                 if (WARN_ON_ONCE(!req))
> 1968                         return 1;
> 1969
> 1970                 i = 0;
> 1971                 do {
> 1972                         slot = req->start_slot + i;
> 1973                         if ((slot == DWC3_TRB_NUM - 1) &&
> 1974                                 usb_endpoint_xfer_isoc(dep->endpoint.desc))

this is executed still with locks held.

> 1975                                 slot++;
> 1976                         slot %= DWC3_TRB_NUM;
> 1977                         trb = &dep->trb_pool[slot];
> 1978
> 1979                         ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
> 1980                                         event, status);
> 1981                         if (ret)
> 1982                                 break;
> 1983                 } while (++i < req->request.num_mapped_sgs);
> 1984
> 1985                 dwc3_gadget_giveback(dep, req, status);

the problem can only show up after this call

> 1986
> 1987                 if (ret)
> 1988                         break;
> 1989         } while (1);
> .......
>
> 2011 static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
> 2012                 struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
> 2013 {
> 2014         unsigned                status = 0;
> 2015         int                     clean_busy;
> 2016         u32                     is_xfer_complete;
> 2017
> 2018         is_xfer_complete = (event->endpoint_event ==
> DWC3_DEPEVT_XFERCOMPLETE);
> 2019
> 2020         if (event->status & DEPEVT_STATUS_BUSERR)
> 2021                 status = -ECONNRESET;
> 2022
> 2023         clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
> 2024         if (clean_busy && (is_xfer_complete ||
> 2025

note the patch I linked you. This is where I added a bail out if the
descriptor is NULL. Here's the patch for reference:

commit 4d100e870616ccd30cf29abf21d437ec746e1f54
Author: Felipe Balbi <felipe.balbi@linux.intel.com>
Date:   Wed May 18 12:37:21 2016 +0300

    usb: dwc3: gadget: fix for possible endpoint disable race
    
    when we call dwc3_gadget_giveback(), we end up
    releasing our controller's lock. Another thread
    could get scheduled and disable the endpoint,
    subsequently setting dep->endpoint.desc to NULL.
    
    In that case, we would end up dereferencing a NULL
    pointer which would result in a Kernel Oops. Let's
    avoid the problem by simply returning early if we
    have a NULL descriptor.
    
    Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f31a59cd5162..3d0573c74b13 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2019,6 +2019,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 			break;
 	} while (1);
 
+	/*
+	 * Our endpoint might get disabled by another thread during
+	 * dwc3_gadget_giveback(). If that happens, we're just gonna return 1
+	 * early on so DWC3_EP_BUSY flag gets cleared
+	 */
+	if (!dep->endpoint.desc)
+		return 1;
+
 	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
 			list_empty(&dep->started_list)) {
 		if (list_empty(&dep->pending_list)) {
@@ -2085,6 +2093,14 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
 		dwc->u1u2 = 0;
 	}
 
+	/*
+	 * Our endpoint might get disabled by another thread during
+	 * dwc3_gadget_giveback(). If that happens, we're just gonna return 1
+	 * early on so DWC3_EP_BUSY flag gets cleared
+	 */
+	if (!dep->endpoint.desc)
+		return;
+
 	if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 		int ret;

Also note that the usb_endpoint_xfer_isoc() call on line 2067 of
gadget.c (as in my testing/next from today) won't even get executed, so
we're safe there.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

  reply	other threads:[~2016-05-26  7:52 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-26  4:58 [PATCH] dwc3: gadget: Introduce dwc3_endpoint_xfer_xxx() to check endpoint type Baolin Wang
2016-05-26  6:22 ` Felipe Balbi
2016-05-26  7:11   ` Baolin Wang
2016-05-26  7:48     ` Felipe Balbi [this message]
2016-05-26  8:24       ` Baolin Wang
2016-05-26  9:45         ` Felipe Balbi
2016-05-26 10:27           ` Baolin Wang
2016-05-26 10:27             ` Felipe Balbi
2016-05-26 10:34               ` Baolin Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8760u1qmxl.fsf@linux.intel.com \
    --to=balbi@kernel.org \
    --cc=baolin.wang@linaro.org \
    --cc=broonie@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.