* Inconsistency in usb_add_gadget_udc_release() interface
@ 2017-08-15 21:39 Alexey Khoroshilov
2017-08-16 6:59 ` Felipe Balbi
2017-08-16 15:24 ` Alan Stern
0 siblings, 2 replies; 5+ messages in thread
From: Alexey Khoroshilov @ 2017-08-15 21:39 UTC (permalink / raw)
To: Felipe Balbi, Greg Kroah-Hartman
Cc: Alexey Khoroshilov, Krzysztof Opasiak, Anton Vasilyev, linux-usb,
linux-kernel, ldv-project
Hello,
usb_add_gadget_udc_release() gets release() argument that allows to
release user resources.
As far as I can see, the release() is called on error paths
of usb_add_gadget_udc_release() as a result of
put_device(&gadget->dev);
except for the only path going via err1.
As a result a caller of the usb_add_gadget_udc_release() have no chance
to know if the release() was invoked or not.
It may lead to memory leaks (drivers/usb/gadget/udc/snps_udc_core.c)
or to double free (drivers/usb/gadget/udc/fsl_udc_core.c).
Is my reading correct? If so, should we always call release() on error paths?
--
Alexey Khoroshilov
Linux Verification Center, ISPRAS
web: http://linuxtesting.org
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Inconsistency in usb_add_gadget_udc_release() interface
2017-08-15 21:39 Inconsistency in usb_add_gadget_udc_release() interface Alexey Khoroshilov
@ 2017-08-16 6:59 ` Felipe Balbi
2017-08-16 15:24 ` Alan Stern
1 sibling, 0 replies; 5+ messages in thread
From: Felipe Balbi @ 2017-08-16 6:59 UTC (permalink / raw)
To: Alexey Khoroshilov, Greg Kroah-Hartman
Cc: Alexey Khoroshilov, Krzysztof Opasiak, Anton Vasilyev, linux-usb,
linux-kernel, ldv-project
[-- Attachment #1: Type: text/plain, Size: 873 bytes --]
Hi,
Alexey Khoroshilov <khoroshilov@ispras.ru> writes:
> Hello,
>
> usb_add_gadget_udc_release() gets release() argument that allows to
> release user resources.
>
> As far as I can see, the release() is called on error paths
> of usb_add_gadget_udc_release() as a result of
> put_device(&gadget->dev);
> except for the only path going via err1.
>
> As a result a caller of the usb_add_gadget_udc_release() have no chance
> to know if the release() was invoked or not.
>
> It may lead to memory leaks (drivers/usb/gadget/udc/snps_udc_core.c)
> or to double free (drivers/usb/gadget/udc/fsl_udc_core.c).
>
> Is my reading correct? If so, should we always call release() on error paths?
unfortunately, it's not :-)
Note that we don't register gadget->dev until later in the code, so
there's nothing to be ->released() that early.
--
balbi
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Inconsistency in usb_add_gadget_udc_release() interface
2017-08-15 21:39 Inconsistency in usb_add_gadget_udc_release() interface Alexey Khoroshilov
2017-08-16 6:59 ` Felipe Balbi
@ 2017-08-16 15:24 ` Alan Stern
2017-08-16 21:15 ` Alexey Khoroshilov
1 sibling, 1 reply; 5+ messages in thread
From: Alan Stern @ 2017-08-16 15:24 UTC (permalink / raw)
To: Alexey Khoroshilov
Cc: Felipe Balbi, Greg Kroah-Hartman, Krzysztof Opasiak,
Anton Vasilyev, linux-usb, linux-kernel, ldv-project
On Wed, 16 Aug 2017, Alexey Khoroshilov wrote:
> Hello,
>
> usb_add_gadget_udc_release() gets release() argument that allows to
> release user resources.
>
> As far as I can see, the release() is called on error paths
> of usb_add_gadget_udc_release() as a result of
> put_device(&gadget->dev);
> except for the only path going via err1.
>
> As a result a caller of the usb_add_gadget_udc_release() have no chance
> to know if the release() was invoked or not.
>
> It may lead to memory leaks (drivers/usb/gadget/udc/snps_udc_core.c)
> or to double free (drivers/usb/gadget/udc/fsl_udc_core.c).
>
> Is my reading correct? If so, should we always call release() on error paths?
How about this (untested)?
Alan Stern
Index: usb-4.x/drivers/usb/gadget/udc/core.c
===================================================================
--- usb-4.x.orig/drivers/usb/gadget/udc/core.c
+++ usb-4.x/drivers/usb/gadget/udc/core.c
@@ -1137,10 +1137,6 @@ int usb_add_gadget_udc_release(struct de
struct usb_udc *udc;
int ret = -ENOMEM;
- udc = kzalloc(sizeof(*udc), GFP_KERNEL);
- if (!udc)
- goto err1;
-
dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent;
@@ -1150,7 +1146,13 @@ int usb_add_gadget_udc_release(struct de
else
gadget->dev.release = usb_udc_nop_release;
- ret = device_register(&gadget->dev);
+ device_initialize(&gadget->dev);
+
+ udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+ if (!udc)
+ goto err1;
+
+ ret = device_add(&gadget->dev);
if (ret)
goto err2;
@@ -1197,10 +1199,10 @@ err3:
device_del(&gadget->dev);
err2:
- put_device(&gadget->dev);
kfree(udc);
err1:
+ put_device(&gadget->dev);
return ret;
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Inconsistency in usb_add_gadget_udc_release() interface
2017-08-16 15:24 ` Alan Stern
@ 2017-08-16 21:15 ` Alexey Khoroshilov
2017-08-17 18:49 ` [PATCH] USB: Gadget core: fix inconsistency in the interface tousb_add_gadget_udc_release() Alan Stern
0 siblings, 1 reply; 5+ messages in thread
From: Alexey Khoroshilov @ 2017-08-16 21:15 UTC (permalink / raw)
To: Alan Stern
Cc: Felipe Balbi, Greg Kroah-Hartman, Krzysztof Opasiak,
Anton Vasilyev, linux-usb, linux-kernel, ldv-project
On 16.08.2017 18:24, Alan Stern wrote:
> On Wed, 16 Aug 2017, Alexey Khoroshilov wrote:
>
>> Hello,
>>
>> usb_add_gadget_udc_release() gets release() argument that allows to
>> release user resources.
>>
>> As far as I can see, the release() is called on error paths
>> of usb_add_gadget_udc_release() as a result of
>> put_device(&gadget->dev);
>> except for the only path going via err1.
>>
>> As a result a caller of the usb_add_gadget_udc_release() have no chance
>> to know if the release() was invoked or not.
>>
>> It may lead to memory leaks (drivers/usb/gadget/udc/snps_udc_core.c)
>> or to double free (drivers/usb/gadget/udc/fsl_udc_core.c).
>>
>> Is my reading correct? If so, should we always call release() on error paths?
>
> How about this (untested)?
>
It looks reasonable. I would only suggest also to make contract
description more explicit, e.g.
/**
* usb_add_gadget_udc_release - adds a new gadget to the udc class
driver list
* @parent: the parent device to this udc. Usually the controller driver's
* device.
* @gadget: the gadget to be added to the list.
* @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
+* Calls the gadget release function in the latter case.
*/
--
Alexey Khoroshilov
Linux Verification Center, ISPRAS
web: http://linuxtesting.org
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH] USB: Gadget core: fix inconsistency in the interface tousb_add_gadget_udc_release()
2017-08-16 21:15 ` Alexey Khoroshilov
@ 2017-08-17 18:49 ` Alan Stern
0 siblings, 0 replies; 5+ messages in thread
From: Alan Stern @ 2017-08-17 18:49 UTC (permalink / raw)
To: Felipe Balbi, Alexey Khoroshilov
Cc: Greg Kroah-Hartman, Krzysztof Opasiak, Anton Vasilyev, USB list,
Kernel development list, ldv-project
The usb_add_gadget_udc_release() routine in the USB gadget core will
sometimes but not always call the gadget's release function when an
error occurs. More specifically, if the struct usb_udc allocation
fails then the release function is not called, and for other errors it
is.
As a result, users of this routine cannot know whether they need to
deallocate the memory containing the gadget structure following an
error. This leads to unavoidable memory leaks or double frees.
This patch fixes the problem by splitting the existing
device_register() call into device_initialize() and device_add(), and
doing the udc allocation in between. That way, even if the allocation
fails it is still possible to call device_del(), and so the release
function will be always called following an error.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
---
[as1837]
drivers/usb/gadget/udc/core.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
Index: usb-4.x/drivers/usb/gadget/udc/core.c
===================================================================
--- usb-4.x.orig/drivers/usb/gadget/udc/core.c
+++ usb-4.x/drivers/usb/gadget/udc/core.c
@@ -1130,6 +1130,7 @@ static int check_pending_gadget_drivers(
* @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
+ * Calls the gadget release function in the latter case.
*/
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
@@ -1137,10 +1138,6 @@ int usb_add_gadget_udc_release(struct de
struct usb_udc *udc;
int ret = -ENOMEM;
- udc = kzalloc(sizeof(*udc), GFP_KERNEL);
- if (!udc)
- goto err1;
-
dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent;
@@ -1150,7 +1147,13 @@ int usb_add_gadget_udc_release(struct de
else
gadget->dev.release = usb_udc_nop_release;
- ret = device_register(&gadget->dev);
+ device_initialize(&gadget->dev);
+
+ udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+ if (!udc)
+ goto err1;
+
+ ret = device_add(&gadget->dev);
if (ret)
goto err2;
@@ -1197,10 +1200,10 @@ err3:
device_del(&gadget->dev);
err2:
- put_device(&gadget->dev);
kfree(udc);
err1:
+ put_device(&gadget->dev);
return ret;
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-08-17 18:49 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-08-15 21:39 Inconsistency in usb_add_gadget_udc_release() interface Alexey Khoroshilov
2017-08-16 6:59 ` Felipe Balbi
2017-08-16 15:24 ` Alan Stern
2017-08-16 21:15 ` Alexey Khoroshilov
2017-08-17 18:49 ` [PATCH] USB: Gadget core: fix inconsistency in the interface tousb_add_gadget_udc_release() Alan Stern
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox