diff mbox series

[v3] device property: fix of node refcount leak in fwnode_graph_get_next_endpoint()

Message ID 20221123022542.2999510-1-yangyingliang@huawei.com (mailing list archive)
State Handled Elsewhere, archived
Headers show
Series [v3] device property: fix of node refcount leak in fwnode_graph_get_next_endpoint() | expand

Commit Message

Yang Yingliang Nov. 23, 2022, 2:25 a.m. UTC
The 'parent' returned by fwnode_graph_get_port_parent()
with refcount incremented when 'prev' is not NULL, it
needs be put when finish using it.

Because the parent is const, introduce a new variable to
store the returned fwnode, then put it before returning
from fwnode_graph_get_next_endpoint().

Fixes: b5b41ab6b0c1 ("device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint()")
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
---
v2 -> v3:
  Add a out label.

v1 -> v2:
  Introduce a new variable to store the returned fwnode.
---
 drivers/base/property.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Comments

Andy Shevchenko Nov. 23, 2022, 1:31 p.m. UTC | #1
On Wed, Nov 23, 2022 at 10:25:42AM +0800, Yang Yingliang wrote:
> The 'parent' returned by fwnode_graph_get_port_parent()
> with refcount incremented when 'prev' is not NULL, it
> needs be put when finish using it.
> 
> Because the parent is const, introduce a new variable to
> store the returned fwnode, then put it before returning
> from fwnode_graph_get_next_endpoint().

To me this looks good enough. Not sure if Dan has a chance (time) to look at
this, though. And maybe even test...

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Fixes: b5b41ab6b0c1 ("device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint()")
> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
> ---
> v2 -> v3:
>   Add a out label.
> 
> v1 -> v2:
>   Introduce a new variable to store the returned fwnode.
> ---
>  drivers/base/property.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/base/property.c b/drivers/base/property.c
> index 2a5a37fcd998..7f338cb4fb7b 100644
> --- a/drivers/base/property.c
> +++ b/drivers/base/property.c
> @@ -989,26 +989,32 @@ struct fwnode_handle *
>  fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
>  			       struct fwnode_handle *prev)
>  {
> +	struct fwnode_handle *ep, *port_parent = NULL;
>  	const struct fwnode_handle *parent;
> -	struct fwnode_handle *ep;
>  
>  	/*
>  	 * If this function is in a loop and the previous iteration returned
>  	 * an endpoint from fwnode->secondary, then we need to use the secondary
>  	 * as parent rather than @fwnode.
>  	 */
> -	if (prev)
> -		parent = fwnode_graph_get_port_parent(prev);
> -	else
> +	if (prev) {
> +		port_parent = fwnode_graph_get_port_parent(prev);
> +		parent = port_parent;
> +	} else {
>  		parent = fwnode;
> +	}
>  	if (IS_ERR_OR_NULL(parent))
>  		return NULL;
>  
>  	ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
>  	if (ep)
> -		return ep;
> +		goto out_put_port_parent;
> +
> +	ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
>  
> -	return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
> +out_put_port_parent:
> +	fwnode_handle_put(port_parent);
> +	return ep;
>  }
>  EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
>  
> -- 
> 2.25.1
>
Daniel Scally Nov. 25, 2022, 9:32 a.m. UTC | #2
Hello

On 23/11/2022 13:31, Andy Shevchenko wrote:
> On Wed, Nov 23, 2022 at 10:25:42AM +0800, Yang Yingliang wrote:
>> The 'parent' returned by fwnode_graph_get_port_parent()
>> with refcount incremented when 'prev' is not NULL, it
>> needs be put when finish using it.
>>
>> Because the parent is const, introduce a new variable to
>> store the returned fwnode, then put it before returning
>> from fwnode_graph_get_next_endpoint().
> To me this looks good enough. Not sure if Dan has a chance (time) to look at
> this, though. And maybe even test...
>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>


Apologies; didn't notice this earlier. I will look at and test this today

>
>> Fixes: b5b41ab6b0c1 ("device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint()")
>> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
>> ---
>> v2 -> v3:
>>   Add a out label.
>>
>> v1 -> v2:
>>   Introduce a new variable to store the returned fwnode.
>> ---
>>  drivers/base/property.c | 18 ++++++++++++------
>>  1 file changed, 12 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/base/property.c b/drivers/base/property.c
>> index 2a5a37fcd998..7f338cb4fb7b 100644
>> --- a/drivers/base/property.c
>> +++ b/drivers/base/property.c
>> @@ -989,26 +989,32 @@ struct fwnode_handle *
>>  fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
>>  			       struct fwnode_handle *prev)
>>  {
>> +	struct fwnode_handle *ep, *port_parent = NULL;
>>  	const struct fwnode_handle *parent;
>> -	struct fwnode_handle *ep;
>>  
>>  	/*
>>  	 * If this function is in a loop and the previous iteration returned
>>  	 * an endpoint from fwnode->secondary, then we need to use the secondary
>>  	 * as parent rather than @fwnode.
>>  	 */
>> -	if (prev)
>> -		parent = fwnode_graph_get_port_parent(prev);
>> -	else
>> +	if (prev) {
>> +		port_parent = fwnode_graph_get_port_parent(prev);
>> +		parent = port_parent;
>> +	} else {
>>  		parent = fwnode;
>> +	}
>>  	if (IS_ERR_OR_NULL(parent))
>>  		return NULL;
>>  
>>  	ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
>>  	if (ep)
>> -		return ep;
>> +		goto out_put_port_parent;
>> +
>> +	ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
>>  
>> -	return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
>> +out_put_port_parent:
>> +	fwnode_handle_put(port_parent);
>> +	return ep;
>>  }
>>  EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
>>  
>> -- 
>> 2.25.1
>>
Yang Yingliang Nov. 25, 2022, 9:49 a.m. UTC | #3
On 2022/11/25 17:32, Daniel Scally wrote:
> Hello
>
> On 23/11/2022 13:31, Andy Shevchenko wrote:
>> On Wed, Nov 23, 2022 at 10:25:42AM +0800, Yang Yingliang wrote:
>>> The 'parent' returned by fwnode_graph_get_port_parent()
>>> with refcount incremented when 'prev' is not NULL, it
>>> needs be put when finish using it.
>>>
>>> Because the parent is const, introduce a new variable to
>>> store the returned fwnode, then put it before returning
>>> from fwnode_graph_get_next_endpoint().
>> To me this looks good enough. Not sure if Dan has a chance (time) to look at
>> this, though. And maybe even test...
>>
>> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Apologies; didn't notice this earlier. I will look at and test this today

Thanks,

I tested it, without this patch, I got this message:
OF: ERROR: memory leak, expected refcount 1 instead of 4, 
of_node_get()/of_node_put() unbalanced - destroy cset entry: attach 
overlay node /i2c/pmic@34/tcpc/connector
after this patch,  the message is gone.
>
>>> Fixes: b5b41ab6b0c1 ("device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint()")
>>> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
>>> ---
>>> v2 -> v3:
>>>    Add a out label.
>>>
>>> v1 -> v2:
>>>    Introduce a new variable to store the returned fwnode.
>>> ---
>>>   drivers/base/property.c | 18 ++++++++++++------
>>>   1 file changed, 12 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/drivers/base/property.c b/drivers/base/property.c
>>> index 2a5a37fcd998..7f338cb4fb7b 100644
>>> --- a/drivers/base/property.c
>>> +++ b/drivers/base/property.c
>>> @@ -989,26 +989,32 @@ struct fwnode_handle *
>>>   fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
>>>   			       struct fwnode_handle *prev)
>>>   {
>>> +	struct fwnode_handle *ep, *port_parent = NULL;
>>>   	const struct fwnode_handle *parent;
>>> -	struct fwnode_handle *ep;
>>>   
>>>   	/*
>>>   	 * If this function is in a loop and the previous iteration returned
>>>   	 * an endpoint from fwnode->secondary, then we need to use the secondary
>>>   	 * as parent rather than @fwnode.
>>>   	 */
>>> -	if (prev)
>>> -		parent = fwnode_graph_get_port_parent(prev);
>>> -	else
>>> +	if (prev) {
>>> +		port_parent = fwnode_graph_get_port_parent(prev);
>>> +		parent = port_parent;
>>> +	} else {
>>>   		parent = fwnode;
>>> +	}
>>>   	if (IS_ERR_OR_NULL(parent))
>>>   		return NULL;
>>>   
>>>   	ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
>>>   	if (ep)
>>> -		return ep;
>>> +		goto out_put_port_parent;
>>> +
>>> +	ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
>>>   
>>> -	return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
>>> +out_put_port_parent:
>>> +	fwnode_handle_put(port_parent);
>>> +	return ep;
>>>   }
>>>   EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
>>>   
>>> -- 
>>> 2.25.1
>>>
> .
Sakari Ailus Nov. 25, 2022, 9:59 a.m. UTC | #4
Hi Yang,

Thank you for the patch.

On Wed, Nov 23, 2022 at 10:25:42AM +0800, Yang Yingliang wrote:
> The 'parent' returned by fwnode_graph_get_port_parent()
> with refcount incremented when 'prev' is not NULL, it
> needs be put when finish using it.
> 
> Because the parent is const, introduce a new variable to
> store the returned fwnode, then put it before returning
> from fwnode_graph_get_next_endpoint().
> 
> Fixes: b5b41ab6b0c1 ("device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint()")
> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>

Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Daniel Scally Nov. 25, 2022, 3:50 p.m. UTC | #5
Hi all - sorry that took so long

On 23/11/2022 02:25, Yang Yingliang wrote:
> The 'parent' returned by fwnode_graph_get_port_parent()
> with refcount incremented when 'prev' is not NULL, it
> needs be put when finish using it.
>
> Because the parent is const, introduce a new variable to
> store the returned fwnode, then put it before returning
> from fwnode_graph_get_next_endpoint().
>
> Fixes: b5b41ab6b0c1 ("device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint()")
> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
> ---


This looks fine to me (thanks for fixing it), and it works fine on my
Surface:


Reviewed-and-tested-by: Daniel Scally <djrscally@gmail.com>

> v2 -> v3:
>   Add a out label.
>
> v1 -> v2:
>   Introduce a new variable to store the returned fwnode.
> ---
>  drivers/base/property.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/base/property.c b/drivers/base/property.c
> index 2a5a37fcd998..7f338cb4fb7b 100644
> --- a/drivers/base/property.c
> +++ b/drivers/base/property.c
> @@ -989,26 +989,32 @@ struct fwnode_handle *
>  fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
>  			       struct fwnode_handle *prev)
>  {
> +	struct fwnode_handle *ep, *port_parent = NULL;
>  	const struct fwnode_handle *parent;
> -	struct fwnode_handle *ep;
>  
>  	/*
>  	 * If this function is in a loop and the previous iteration returned
>  	 * an endpoint from fwnode->secondary, then we need to use the secondary
>  	 * as parent rather than @fwnode.
>  	 */
> -	if (prev)
> -		parent = fwnode_graph_get_port_parent(prev);
> -	else
> +	if (prev) {
> +		port_parent = fwnode_graph_get_port_parent(prev);
> +		parent = port_parent;
> +	} else {
>  		parent = fwnode;
> +	}
>  	if (IS_ERR_OR_NULL(parent))
>  		return NULL;
>  
>  	ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
>  	if (ep)
> -		return ep;
> +		goto out_put_port_parent;
> +
> +	ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
>  
> -	return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
> +out_put_port_parent:
> +	fwnode_handle_put(port_parent);
> +	return ep;
>  }
>  EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
>
Andy Shevchenko Dec. 28, 2022, 9:37 a.m. UTC | #6
On Wed, Nov 23, 2022 at 10:25:42AM +0800, Yang Yingliang wrote:
> The 'parent' returned by fwnode_graph_get_port_parent()
> with refcount incremented when 'prev' is not NULL, it
> needs be put when finish using it.
> 
> Because the parent is const, introduce a new variable to
> store the returned fwnode, then put it before returning
> from fwnode_graph_get_next_endpoint().

Rafael, Greg, is this went through the cracks?
Greg KH Dec. 28, 2022, 9:46 a.m. UTC | #7
On Wed, Dec 28, 2022 at 11:37:15AM +0200, Andy Shevchenko wrote:
> On Wed, Nov 23, 2022 at 10:25:42AM +0800, Yang Yingliang wrote:
> > The 'parent' returned by fwnode_graph_get_port_parent()
> > with refcount incremented when 'prev' is not NULL, it
> > needs be put when finish using it.
> > 
> > Because the parent is const, introduce a new variable to
> > store the returned fwnode, then put it before returning
> > from fwnode_graph_get_next_endpoint().
> 
> Rafael, Greg, is this went through the cracks?

Yes, but still in my queue.  I'll look at it when I get back from break.

thanks,

greg k-h
Andy Shevchenko Dec. 28, 2022, 9:50 a.m. UTC | #8
On Wed, Dec 28, 2022 at 10:46:12AM +0100, Greg KH wrote:
> On Wed, Dec 28, 2022 at 11:37:15AM +0200, Andy Shevchenko wrote:
> > On Wed, Nov 23, 2022 at 10:25:42AM +0800, Yang Yingliang wrote:
> > > The 'parent' returned by fwnode_graph_get_port_parent()
> > > with refcount incremented when 'prev' is not NULL, it
> > > needs be put when finish using it.
> > > 
> > > Because the parent is const, introduce a new variable to
> > > store the returned fwnode, then put it before returning
> > > from fwnode_graph_get_next_endpoint().
> > 
> > Rafael, Greg, is this went through the cracks?
> 
> Yes, but still in my queue.  I'll look at it when I get back from break.

Have a nice one!
diff mbox series

Patch

diff --git a/drivers/base/property.c b/drivers/base/property.c
index 2a5a37fcd998..7f338cb4fb7b 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -989,26 +989,32 @@  struct fwnode_handle *
 fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
 			       struct fwnode_handle *prev)
 {
+	struct fwnode_handle *ep, *port_parent = NULL;
 	const struct fwnode_handle *parent;
-	struct fwnode_handle *ep;
 
 	/*
 	 * If this function is in a loop and the previous iteration returned
 	 * an endpoint from fwnode->secondary, then we need to use the secondary
 	 * as parent rather than @fwnode.
 	 */
-	if (prev)
-		parent = fwnode_graph_get_port_parent(prev);
-	else
+	if (prev) {
+		port_parent = fwnode_graph_get_port_parent(prev);
+		parent = port_parent;
+	} else {
 		parent = fwnode;
+	}
 	if (IS_ERR_OR_NULL(parent))
 		return NULL;
 
 	ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
 	if (ep)
-		return ep;
+		goto out_put_port_parent;
+
+	ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
 
-	return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
+out_put_port_parent:
+	fwnode_handle_put(port_parent);
+	return ep;
 }
 EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);