diff mbox

usb: dwc2: gadget: Fix memory leak in dwc2_gadget_init()

Message ID f37e289c25f9219112b866153f35679836ef12a4.1523870350.git.tovmasya@synopsys.com (mailing list archive)
State New, archived
Headers show

Commit Message

Grigor Tovmasyan April 16, 2018, 10:16 a.m. UTC
In dwc2_gadget_init() we allocate EP0 request via
dwc2_hsotg_ep_alloc_request(). After that there are
usb_add_gadget_udc() call and if it failed, then
ctrl_req will not be freed and will cause memory leak.

Reordered function calls in gadget_init: moved up usb_add_gadget_udc()
before dwc2_hsotg_ep_alloc_request().

Tested using kmemleak.

Cc: Stefan Wahren <stefan.wahren@i2se.com>
Signed-off-by: Grigor Tovmasyan <tovmasya@synopsys.com>
---
 drivers/usb/dwc2/gadget.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Comments

Stefan Wahren April 17, 2018, 9:10 p.m. UTC | #1
Hi Grigor,

> Grigor Tovmasyan <Grigor.Tovmasyan@synopsys.com> hat am 16. April 2018 um 12:16 geschrieben:
> 
> 
> In dwc2_gadget_init() we allocate EP0 request via
> dwc2_hsotg_ep_alloc_request(). After that there are
> usb_add_gadget_udc() call and if it failed, then
> ctrl_req will not be freed and will cause memory leak.
> 
> Reordered function calls in gadget_init: moved up usb_add_gadget_udc()
> before dwc2_hsotg_ep_alloc_request().

i'm not sure, but doesn't this change introduce a race condition before EP0 request has been allocated?

Stefan
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grigor Tovmasyan April 23, 2018, 7:05 a.m. UTC | #2
Hi Stefan,

On 4/18/2018 1:11 AM, Stefan Wahren wrote:
> Hi Grigor,
> 
>> Grigor Tovmasyan <Grigor.Tovmasyan@synopsys.com> hat am 16. April 2018 um 12:16 geschrieben:
>>
>>
>> In dwc2_gadget_init() we allocate EP0 request via
>> dwc2_hsotg_ep_alloc_request(). After that there are
>> usb_add_gadget_udc() call and if it failed, then
>> ctrl_req will not be freed and will cause memory leak.
>>
>> Reordered function calls in gadget_init: moved up usb_add_gadget_udc()
>> before dwc2_hsotg_ep_alloc_request().
> 
> i'm not sure, but doesn't this change introduce a race condition before EP0 request has been allocated?
As far as I know the firt request to EP0 coming when the function driver 
first bind() to the device, which happens after dwc2 probe.
So, in my opinion this patch is safe.

Grigor
> 
> Stefan
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stefan Wahren April 23, 2018, 8:51 a.m. UTC | #3
Am 23.04.2018 um 09:05 schrieb Grigor Tovmasyan:
> Hi Stefan,
>
> On 4/18/2018 1:11 AM, Stefan Wahren wrote:
>> Hi Grigor,
>>
>>> Grigor Tovmasyan <Grigor.Tovmasyan@synopsys.com> hat am 16. April 2018 um 12:16 geschrieben:
>>>
>>>
>>> In dwc2_gadget_init() we allocate EP0 request via
>>> dwc2_hsotg_ep_alloc_request(). After that there are
>>> usb_add_gadget_udc() call and if it failed, then
>>> ctrl_req will not be freed and will cause memory leak.
>>>
>>> Reordered function calls in gadget_init: moved up usb_add_gadget_udc()
>>> before dwc2_hsotg_ep_alloc_request().
>> i'm not sure, but doesn't this change introduce a race condition before EP0 request has been allocated?
> As far as I know the firt request to EP0 coming when the function driver
> first bind() to the device, which happens after dwc2 probe.
> So, in my opinion this patch is safe.
okay fine
>
> Grigor
>> Stefan
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Minas Harutyunyan May 15, 2018, 10:12 a.m. UTC | #4
On 4/16/2018 2:16 PM, Grigor Tovmasyan wrote:
> In dwc2_gadget_init() we allocate EP0 request via
> dwc2_hsotg_ep_alloc_request(). After that there are
> usb_add_gadget_udc() call and if it failed, then
> ctrl_req will not be freed and will cause memory leak.
> 
> Reordered function calls in gadget_init: moved up usb_add_gadget_udc()
> before dwc2_hsotg_ep_alloc_request().
> 
> Tested using kmemleak.
> 
> Cc: Stefan Wahren <stefan.wahren@i2se.com>
> Signed-off-by: Grigor Tovmasyan <tovmasya@synopsys.com>
> ---

Acked-by: Minas Harutyunyan <hminas@synopsys.com>

>   drivers/usb/dwc2/gadget.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
> index 6c32bf26e48e..24000bda5c20 100644
> --- a/drivers/usb/dwc2/gadget.c
> +++ b/drivers/usb/dwc2/gadget.c
> @@ -4679,6 +4679,10 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
>   	INIT_LIST_HEAD(&hsotg->gadget.ep_list);
>   	hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep;
>   
> +	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
> +	if (ret)
> +		return ret;
> +
>   	/* allocate EP0 request */
>   
>   	hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep,
> @@ -4698,10 +4702,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
>   					  epnum, 0);
>   	}
>   
> -	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
> -	if (ret)
> -		return ret;
> -
>   	dwc2_hsotg_dump(hsotg);
>   
>   	return 0;
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Szyprowski May 17, 2018, 12:18 p.m. UTC | #5
Hi All,

I've just noticed this patch has been applied to linux-next.

It breaks DWC2 driver initialization on Samsung Exynos-based boards
I've use for kernel daily tests.

Here is an example of the call stack:

Unable to handle kernel NULL pointer dereference at virtual address 0000000c
pgd = (ptrval)
[0000000c] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 0 PID: 25 Comm: kworker/0:1 Not tainted 4.17.0-rc5-next-20180517 #782
Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
Workqueue: events deferred_probe_work_func
PC is at usb_ep_alloc_request+0x1c/0x200
LR is at composite_dev_prepare+0x20/0xec
pc : [<c06976a8>]    lr : [<c0694744>]    psr: 60000153
sp : d95f1d10  ip : 00000000  fp : 00000002
r10: c1072d58  r9 : d82443d0  r8 : 00000000
r7 : c1074180  r6 : c10ad460  r5 : c100746c  r4 : d8253980
r3 : 00000000  r2 : d82539b8  r1 : 014000c0  r0 : d82443d0
Flags: nZCv  IRQs on  FIQs off  Mode SVC_32  ISA ARM  Segment none
Control: 10c5387d  Table: 4000406a  DAC: 00000051
Process kworker/0:1 (pid: 25, stack limit = 0x(ptrval))
Stack: (0xd95f1d10 to 0xd95f2000)
...
[<c06976a8>] (usb_ep_alloc_request) from [<c0694744>] 
(composite_dev_prepare+0x20/0xec)
[<c0694744>] (composite_dev_prepare) from [<c0694b4c>] 
(composite_bind+0x7c/0x1c8)
[<c0694b4c>] (composite_bind) from [<c069a8e0>] 
(udc_bind_to_driver+0x74/0x134)
[<c069a8e0>] (udc_bind_to_driver) from [<c069aa14>] 
(check_pending_gadget_drivers+0x74/0xac)
[<c069aa14>] (check_pending_gadget_drivers) from [<c069abdc>] 
(usb_add_gadget_udc_release+0x190/0x1ec)
[<c069abdc>] (usb_add_gadget_udc_release) from [<c0655a84>] 
(dwc2_gadget_init+0x274/0x464)
[<c0655a84>] (dwc2_gadget_init) from [<c0642fb0>] 
(dwc2_driver_probe+0x488/0x50c)
[<c0642fb0>] (dwc2_driver_probe) from [<c057a1e4>] 
(platform_drv_probe+0x48/0x9c)
[<c057a1e4>] (platform_drv_probe) from [<c0577d54>] 
(driver_probe_device+0x2dc/0x4ac)
[<c0577d54>] (driver_probe_device) from [<c0575d54>] 
(bus_for_each_drv+0x74/0xb8)
[<c0575d54>] (bus_for_each_drv) from [<c057792c>] 
(__device_attach+0xd4/0x168)
[<c057792c>] (__device_attach) from [<c0576bf8>] 
(bus_probe_device+0x88/0x90)
[<c0576bf8>] (bus_probe_device) from [<c05771b0>] 
(deferred_probe_work_func+0x60/0x180)
[<c05771b0>] (deferred_probe_work_func) from ad+0x28c/0x58c)
[<c0147f2c>] (worker_thread) from [<c014dc5c>] (kthread+0x138/0x168)
[<c014dc5c>] (kthread) from [<c01010b4>] (ret_from_fork+0x14/0x20)


A proper fix for the potential memory leak is to add free to error path
instead of reordering usb_add_gadget_udc() call. The issue happens if DWC2
driver is initialized from deferred probe (in such case the gadget driver
is already registered).

Felipe: please drop or revert this patch in your -next branch.


Best regards
Marek Szyprowski, PhD
Samsung R&D Institute Poland

On 2018-04-16 12:16, Grigor Tovmasyan wrote:
> In dwc2_gadget_init() we allocate EP0 request via
> dwc2_hsotg_ep_alloc_request(). After that there are
> usb_add_gadget_udc() call and if it failed, then
> ctrl_req will not be freed and will cause memory leak.
>
> Reordered function calls in gadget_init: moved up usb_add_gadget_udc()
> before dwc2_hsotg_ep_alloc_request().
>
> Tested using kmemleak.
>
> Cc: Stefan Wahren <stefan.wahren@i2se.com>
> Signed-off-by: Grigor Tovmasyan <tovmasya@synopsys.com>
> Acked-by: Minas Harutyunyan <hminas@synopsys.com>
> ---
>   drivers/usb/dwc2/gadget.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
> index 6c32bf26e48e..24000bda5c20 100644
> --- a/drivers/usb/dwc2/gadget.c
> +++ b/drivers/usb/dwc2/gadget.c
> @@ -4679,6 +4679,10 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
>   	INIT_LIST_HEAD(&hsotg->gadget.ep_list);
>   	hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep;
>   
> +	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
> +	if (ret)
> +		return ret;
> +
>   	/* allocate EP0 request */
>   
>   	hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep,
> @@ -4698,10 +4702,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
>   					  epnum, 0);
>   	}
>   
> -	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
> -	if (ret)
> -		return ret;
> -
>   	dwc2_hsotg_dump(hsotg);
>   
>   	return 0;
>

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grigor Tovmasyan May 17, 2018, 3:02 p.m. UTC | #6
Hi Felipe,

Please drop this patch from your next branch.
I will provide another fix based on Marek's suggestion.

Thanks,
Grigor.

On 5/17/2018 4:18 PM, Marek Szyprowski wrote:
> Hi All,
> 
> I've just noticed this patch has been applied to linux-next.
> 
> It breaks DWC2 driver initialization on Samsung Exynos-based boards
> I've use for kernel daily tests.
> 
> Here is an example of the call stack:
> 
> Unable to handle kernel NULL pointer dereference at virtual address 0000000c
> pgd = (ptrval)
> [0000000c] *pgd=00000000
> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> Modules linked in:
> CPU: 0 PID: 25 Comm: kworker/0:1 Not tainted 4.17.0-rc5-next-20180517 #782
> Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
> Workqueue: events deferred_probe_work_func
> PC is at usb_ep_alloc_request+0x1c/0x200
> LR is at composite_dev_prepare+0x20/0xec
> pc : [<c06976a8>]    lr : [<c0694744>]    psr: 60000153
> sp : d95f1d10  ip : 00000000  fp : 00000002
> r10: c1072d58  r9 : d82443d0  r8 : 00000000
> r7 : c1074180  r6 : c10ad460  r5 : c100746c  r4 : d8253980
> r3 : 00000000  r2 : d82539b8  r1 : 014000c0  r0 : d82443d0
> Flags: nZCv  IRQs on  FIQs off  Mode SVC_32  ISA ARM  Segment none
> Control: 10c5387d  Table: 4000406a  DAC: 00000051
> Process kworker/0:1 (pid: 25, stack limit = 0x(ptrval))
> Stack: (0xd95f1d10 to 0xd95f2000)
> ...
> [<c06976a8>] (usb_ep_alloc_request) from [<c0694744>]
> (composite_dev_prepare+0x20/0xec)
> [<c0694744>] (composite_dev_prepare) from [<c0694b4c>]
> (composite_bind+0x7c/0x1c8)
> [<c0694b4c>] (composite_bind) from [<c069a8e0>]
> (udc_bind_to_driver+0x74/0x134)
> [<c069a8e0>] (udc_bind_to_driver) from [<c069aa14>]
> (check_pending_gadget_drivers+0x74/0xac)
> [<c069aa14>] (check_pending_gadget_drivers) from [<c069abdc>]
> (usb_add_gadget_udc_release+0x190/0x1ec)
> [<c069abdc>] (usb_add_gadget_udc_release) from [<c0655a84>]
> (dwc2_gadget_init+0x274/0x464)
> [<c0655a84>] (dwc2_gadget_init) from [<c0642fb0>]
> (dwc2_driver_probe+0x488/0x50c)
> [<c0642fb0>] (dwc2_driver_probe) from [<c057a1e4>]
> (platform_drv_probe+0x48/0x9c)
> [<c057a1e4>] (platform_drv_probe) from [<c0577d54>]
> (driver_probe_device+0x2dc/0x4ac)
> [<c0577d54>] (driver_probe_device) from [<c0575d54>]
> (bus_for_each_drv+0x74/0xb8)
> [<c0575d54>] (bus_for_each_drv) from [<c057792c>]
> (__device_attach+0xd4/0x168)
> [<c057792c>] (__device_attach) from [<c0576bf8>]
> (bus_probe_device+0x88/0x90)
> [<c0576bf8>] (bus_probe_device) from [<c05771b0>]
> (deferred_probe_work_func+0x60/0x180)
> [<c05771b0>] (deferred_probe_work_func) from ad+0x28c/0x58c)
> [<c0147f2c>] (worker_thread) from [<c014dc5c>] (kthread+0x138/0x168)
> [<c014dc5c>] (kthread) from [<c01010b4>] (ret_from_fork+0x14/0x20)
> 
> 
> A proper fix for the potential memory leak is to add free to error path
> instead of reordering usb_add_gadget_udc() call. The issue happens if DWC2
> driver is initialized from deferred probe (in such case the gadget driver
> is already registered).
> 
> Felipe: please drop or revert this patch in your -next branch.
> 
> 
> Best regards
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
> 
> On 2018-04-16 12:16, Grigor Tovmasyan wrote:
>> In dwc2_gadget_init() we allocate EP0 request via
>> dwc2_hsotg_ep_alloc_request(). After that there are
>> usb_add_gadget_udc() call and if it failed, then
>> ctrl_req will not be freed and will cause memory leak.
>>
>> Reordered function calls in gadget_init: moved up usb_add_gadget_udc()
>> before dwc2_hsotg_ep_alloc_request().
>>
>> Tested using kmemleak.
>>
>> Cc: Stefan Wahren <stefan.wahren@i2se.com>
>> Signed-off-by: Grigor Tovmasyan <tovmasya@synopsys.com>
>> Acked-by: Minas Harutyunyan <hminas@synopsys.com>
>> ---
>>    drivers/usb/dwc2/gadget.c | 8 ++++----
>>    1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
>> index 6c32bf26e48e..24000bda5c20 100644
>> --- a/drivers/usb/dwc2/gadget.c
>> +++ b/drivers/usb/dwc2/gadget.c
>> @@ -4679,6 +4679,10 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
>>    	INIT_LIST_HEAD(&hsotg->gadget.ep_list);
>>    	hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep;
>>    
>> +	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
>> +	if (ret)
>> +		return ret;
>> +
>>    	/* allocate EP0 request */
>>    
>>    	hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep,
>> @@ -4698,10 +4702,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
>>    					  epnum, 0);
>>    	}
>>    
>> -	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
>> -	if (ret)
>> -		return ret;
>> -
>>    	dwc2_hsotg_dump(hsotg);
>>    
>>    	return 0;
>>
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Felipe Balbi May 21, 2018, 7:01 a.m. UTC | #7
Hi,

Grigor Tovmasyan <Grigor.Tovmasyan@synopsys.com> writes:
> Hi Felipe,
>
> Please drop this patch from your next branch.
> I will provide another fix based on Marek's suggestion.

this time I'll rebase my 'next' branch. Next time, make sure this
doesn't happen anymore as I like my 'next' to be immutable.
diff mbox

Patch

diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 6c32bf26e48e..24000bda5c20 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -4679,6 +4679,10 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
 	INIT_LIST_HEAD(&hsotg->gadget.ep_list);
 	hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep;
 
+	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
+	if (ret)
+		return ret;
+
 	/* allocate EP0 request */
 
 	hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep,
@@ -4698,10 +4702,6 @@  int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
 					  epnum, 0);
 	}
 
-	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
-	if (ret)
-		return ret;
-
 	dwc2_hsotg_dump(hsotg);
 
 	return 0;