mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices
@ 2024-10-15  6:01 Aleksandr Mishin
  2024-10-15  6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-15  6:01 UTC (permalink / raw)
  To: Igal Liberman
  Cc: Aleksandr Mishin, Simon Horman, Madalin Bucur, Sean Anderson,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	netdev, linux-kernel, lvc-project

The series is intended to fix refcount handling for fman-related "struct
device" objects - the devices are not released upon driver removal or in
the error paths during probe. This leads to device reference leaks.

The device pointers are now saved to struct mac_device and properly handled
in the driver's probe and removal functions.

Originally reported by Simon Horman <horms@kernel.org>
(https://lore.kernel.org/all/20240702133651.GK598357@kernel.org/)

Compile tested only.

Aleksandr Mishin (2):
  fsl/fman: Save device references taken in mac_probe()
  fsl/fman: Fix refcount handling of fman-related devices

 drivers/net/ethernet/freescale/fman/mac.c | 68 +++++++++++++++++------
 drivers/net/ethernet/freescale/fman/mac.h |  6 +-
 2 files changed, 56 insertions(+), 18 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe()
  2024-10-15  6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
@ 2024-10-15  6:01 ` Aleksandr Mishin
  2024-10-15  6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
  2024-10-21  9:20 ` [PATCH net 0/2] " patchwork-bot+netdevbpf
  2 siblings, 0 replies; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-15  6:01 UTC (permalink / raw)
  To: Igal Liberman
  Cc: Aleksandr Mishin, Simon Horman, Madalin Bucur, Sean Anderson,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	netdev, linux-kernel, lvc-project

In mac_probe() there are calls to of_find_device_by_node() which takes
references to of_dev->dev. These references are not saved and not released
later on error path in mac_probe() and in mac_remove().

Add new fields into mac_device structure to save references taken for
future use in mac_probe() and mac_remove().

This is a preparation for further reference leaks fix.

Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
---
 drivers/net/ethernet/freescale/fman/mac.c | 6 ++++--
 drivers/net/ethernet/freescale/fman/mac.h | 6 +++++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 9767586b4eb3..9b863db0bf08 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -197,6 +197,7 @@ static int mac_probe(struct platform_device *_of_dev)
 		err = -EINVAL;
 		goto _return_of_node_put;
 	}
+	mac_dev->fman_dev = &of_dev->dev;
 
 	/* Get the FMan cell-index */
 	err = of_property_read_u32(dev_node, "cell-index", &val);
@@ -208,7 +209,7 @@ static int mac_probe(struct platform_device *_of_dev)
 	/* cell-index 0 => FMan id 1 */
 	fman_id = (u8)(val + 1);
 
-	priv->fman = fman_bind(&of_dev->dev);
+	priv->fman = fman_bind(mac_dev->fman_dev);
 	if (!priv->fman) {
 		dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
 		err = -ENODEV;
@@ -284,8 +285,9 @@ static int mac_probe(struct platform_device *_of_dev)
 			err = -EINVAL;
 			goto _return_of_node_put;
 		}
+		mac_dev->fman_port_devs[i] = &of_dev->dev;
 
-		mac_dev->port[i] = fman_port_bind(&of_dev->dev);
+		mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);
 		if (!mac_dev->port[i]) {
 			dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
 				dev_node);
diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethernet/freescale/fman/mac.h
index fe747915cc73..8b5b43d50f8e 100644
--- a/drivers/net/ethernet/freescale/fman/mac.h
+++ b/drivers/net/ethernet/freescale/fman/mac.h
@@ -19,12 +19,13 @@
 struct fman_mac;
 struct mac_priv_s;
 
+#define PORT_NUM 2
 struct mac_device {
 	void __iomem		*vaddr;
 	struct device		*dev;
 	struct resource		*res;
 	u8			 addr[ETH_ALEN];
-	struct fman_port	*port[2];
+	struct fman_port	*port[PORT_NUM];
 	struct phylink		*phylink;
 	struct phylink_config	phylink_config;
 	phy_interface_t		phy_if;
@@ -52,6 +53,9 @@ struct mac_device {
 
 	struct fman_mac		*fman_mac;
 	struct mac_priv_s	*priv;
+
+	struct device		*fman_dev;
+	struct device		*fman_port_devs[PORT_NUM];
 };
 
 static inline struct mac_device
-- 
2.30.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices
  2024-10-15  6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
  2024-10-15  6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
@ 2024-10-15  6:01 ` Aleksandr Mishin
  2024-10-17 10:01   ` Paolo Abeni
  2024-10-21  9:20 ` [PATCH net 0/2] " patchwork-bot+netdevbpf
  2 siblings, 1 reply; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-15  6:01 UTC (permalink / raw)
  To: Igal Liberman
  Cc: Aleksandr Mishin, Simon Horman, Madalin Bucur, Sean Anderson,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	netdev, linux-kernel, lvc-project

In mac_probe() there are multiple calls to of_find_device_by_node(),
fman_bind() and fman_port_bind() which takes references to of_dev->dev.
Not all references taken by these calls are released later on error path
in mac_probe() and in mac_remove() which lead to reference leaks.

Add references release.

Fixes: 3933961682a3 ("fsl/fman: Add FMan MAC driver")
Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
---
Compile tested only.

 drivers/net/ethernet/freescale/fman/mac.c | 62 +++++++++++++++++------
 1 file changed, 47 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 9b863db0bf08..11da139082e1 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -204,7 +204,7 @@ static int mac_probe(struct platform_device *_of_dev)
 	if (err) {
 		dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
 		err = -EINVAL;
-		goto _return_of_node_put;
+		goto _return_dev_put;
 	}
 	/* cell-index 0 => FMan id 1 */
 	fman_id = (u8)(val + 1);
@@ -213,40 +213,51 @@ static int mac_probe(struct platform_device *_of_dev)
 	if (!priv->fman) {
 		dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
 		err = -ENODEV;
-		goto _return_of_node_put;
+		goto _return_dev_put;
 	}
 
+	/* Two references have been taken in of_find_device_by_node()
+	 * and fman_bind(). Release one of them here. The second one
+	 * will be released in mac_remove().
+	 */
+	put_device(mac_dev->fman_dev);
 	of_node_put(dev_node);
+	dev_node = NULL;
 
 	/* Get the address of the memory mapped registers */
 	mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
 	if (!mac_dev->res) {
 		dev_err(dev, "could not get registers\n");
-		return -EINVAL;
+		err = -EINVAL;
+		goto _return_dev_put;
 	}
 
 	err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
 				    mac_dev->res);
 	if (err) {
 		dev_err_probe(dev, err, "could not request resource\n");
-		return err;
+		goto _return_dev_put;
 	}
 
 	mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
 				      resource_size(mac_dev->res));
 	if (!mac_dev->vaddr) {
 		dev_err(dev, "devm_ioremap() failed\n");
-		return -EIO;
+		err = -EIO;
+		goto _return_dev_put;
 	}
 
-	if (!of_device_is_available(mac_node))
-		return -ENODEV;
+	if (!of_device_is_available(mac_node)) {
+		err = -ENODEV;
+		goto _return_dev_put;
+	}
 
 	/* Get the cell-index */
 	err = of_property_read_u32(mac_node, "cell-index", &val);
 	if (err) {
 		dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
-		return -EINVAL;
+		err = -EINVAL;
+		goto _return_dev_put;
 	}
 	priv->cell_index = (u8)val;
 
@@ -260,22 +271,26 @@ static int mac_probe(struct platform_device *_of_dev)
 	if (unlikely(nph < 0)) {
 		dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
 			mac_node);
-		return nph;
+		err = nph;
+		goto _return_dev_put;
 	}
 
 	if (nph != ARRAY_SIZE(mac_dev->port)) {
 		dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
 			mac_node);
-		return -EINVAL;
+		err = -EINVAL;
+		goto _return_dev_put;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) {
+	/* PORT_NUM determines the size of the port array */
+	for (i = 0; i < PORT_NUM; i++) {
 		/* Find the port node */
 		dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
 		if (!dev_node) {
 			dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
 				mac_node);
-			return -EINVAL;
+			err = -EINVAL;
+			goto _return_dev_arr_put;
 		}
 
 		of_dev = of_find_device_by_node(dev_node);
@@ -283,7 +298,7 @@ static int mac_probe(struct platform_device *_of_dev)
 			dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
 				dev_node);
 			err = -EINVAL;
-			goto _return_of_node_put;
+			goto _return_dev_arr_put;
 		}
 		mac_dev->fman_port_devs[i] = &of_dev->dev;
 
@@ -292,9 +307,15 @@ static int mac_probe(struct platform_device *_of_dev)
 			dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
 				dev_node);
 			err = -EINVAL;
-			goto _return_of_node_put;
+			goto _return_dev_arr_put;
 		}
+		/* Two references have been taken in of_find_device_by_node()
+		 * and fman_port_bind(). Release one of them here. The second
+		 * one will be released in mac_remove().
+		 */
+		put_device(mac_dev->fman_port_devs[i]);
 		of_node_put(dev_node);
+		dev_node = NULL;
 	}
 
 	/* Get the PHY connection type */
@@ -314,7 +335,7 @@ static int mac_probe(struct platform_device *_of_dev)
 
 	err = init(mac_dev, mac_node, &params);
 	if (err < 0)
-		return err;
+		goto _return_dev_arr_put;
 
 	if (!is_zero_ether_addr(mac_dev->addr))
 		dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
@@ -329,6 +350,12 @@ static int mac_probe(struct platform_device *_of_dev)
 
 	return err;
 
+_return_dev_arr_put:
+	/* mac_dev is kzalloc'ed */
+	for (i = 0; i < PORT_NUM; i++)
+		put_device(mac_dev->fman_port_devs[i]);
+_return_dev_put:
+	put_device(mac_dev->fman_dev);
 _return_of_node_put:
 	of_node_put(dev_node);
 	return err;
@@ -337,6 +364,11 @@ static int mac_probe(struct platform_device *_of_dev)
 static void mac_remove(struct platform_device *pdev)
 {
 	struct mac_device *mac_dev = platform_get_drvdata(pdev);
+	int		   i;
+
+	for (i = 0; i < PORT_NUM; i++)
+		put_device(mac_dev->fman_port_devs[i]);
+	put_device(mac_dev->fman_dev);
 
 	platform_device_unregister(mac_dev->priv->eth_dev);
 }
-- 
2.30.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices
  2024-10-15  6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
@ 2024-10-17 10:01   ` Paolo Abeni
  2024-10-17 10:53     ` Aleksandr Mishin
  0 siblings, 1 reply; 6+ messages in thread
From: Paolo Abeni @ 2024-10-17 10:01 UTC (permalink / raw)
  To: Aleksandr Mishin, Igal Liberman
  Cc: Simon Horman, Madalin Bucur, Sean Anderson, David S. Miller,
	Eric Dumazet, Jakub Kicinski, netdev, linux-kernel, lvc-project

On 10/15/24 08:01, Aleksandr Mishin wrote:
> In mac_probe() there are multiple calls to of_find_device_by_node(),
> fman_bind() and fman_port_bind() which takes references to of_dev->dev.
> Not all references taken by these calls are released later on error path
> in mac_probe() and in mac_remove() which lead to reference leaks.
> 
> Add references release.
> 
> Fixes: 3933961682a3 ("fsl/fman: Add FMan MAC driver")
> Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
> ---
> Compile tested only.
> 
>   drivers/net/ethernet/freescale/fman/mac.c | 62 +++++++++++++++++------
>   1 file changed, 47 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
> index 9b863db0bf08..11da139082e1 100644
> --- a/drivers/net/ethernet/freescale/fman/mac.c
> +++ b/drivers/net/ethernet/freescale/fman/mac.c
> @@ -204,7 +204,7 @@ static int mac_probe(struct platform_device *_of_dev)
>   	if (err) {
>   		dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
>   		err = -EINVAL;
> -		goto _return_of_node_put;
> +		goto _return_dev_put;

We are after a succesful of_find_device_by_node and prior to 
fman_bind(), mac_dev->fman_dev refcount is 1

> @@ -213,40 +213,51 @@ static int mac_probe(struct platform_device *_of_dev)
>   	if (!priv->fman) {
>   		dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
>   		err = -ENODEV;
> -		goto _return_of_node_put;
> +		goto _return_dev_put;
>   	}
>   
> +	/* Two references have been taken in of_find_device_by_node()
> +	 * and fman_bind(). Release one of them here. The second one
> +	 * will be released in mac_remove().
> +	 */
> +	put_device(mac_dev->fman_dev);
>   	of_node_put(dev_node);
> +	dev_node = NULL;
>   
>   	/* Get the address of the memory mapped registers */
>   	mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
>   	if (!mac_dev->res) {
>   		dev_err(dev, "could not get registers\n");
> -		return -EINVAL;
> +		err = -EINVAL;
> +		goto _return_dev_put;

Here we are after a successful fman_bind(), mac_dev->fman_dev  refcount 
is 2. _return_dev_put will drop a single reference, this error path 
looks buggy.

Similar issue for the _return_dev_arr_put error path below.

Cheers,

Paolo


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices
  2024-10-17 10:01   ` Paolo Abeni
@ 2024-10-17 10:53     ` Aleksandr Mishin
  0 siblings, 0 replies; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-17 10:53 UTC (permalink / raw)
  To: Paolo Abeni, Igal Liberman
  Cc: Simon Horman, Madalin Bucur, Sean Anderson, David S. Miller,
	Eric Dumazet, Jakub Kicinski, netdev, linux-kernel, lvc-project


On 17.10.2024 13:01, Paolo Abeni wrote:
> On 10/15/24 08:01, Aleksandr Mishin wrote:
>> In mac_probe() there are multiple calls to of_find_device_by_node(),
>> fman_bind() and fman_port_bind() which takes references to of_dev->dev.
>> Not all references taken by these calls are released later on error path
>> in mac_probe() and in mac_remove() which lead to reference leaks.
>>
>> Add references release.
>>
>> Fixes: 3933961682a3 ("fsl/fman: Add FMan MAC driver")
>> Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
>> ---
>> Compile tested only.
>>
>>   drivers/net/ethernet/freescale/fman/mac.c | 62 +++++++++++++++++------
>>   1 file changed, 47 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/freescale/fman/mac.c 
>> b/drivers/net/ethernet/freescale/fman/mac.c
>> index 9b863db0bf08..11da139082e1 100644
>> --- a/drivers/net/ethernet/freescale/fman/mac.c
>> +++ b/drivers/net/ethernet/freescale/fman/mac.c
>> @@ -204,7 +204,7 @@ static int mac_probe(struct platform_device 
>> *_of_dev)
>>       if (err) {
>>           dev_err(dev, "failed to read cell-index for %pOF\n", 
>> dev_node);
>>           err = -EINVAL;
>> -        goto _return_of_node_put;
>> +        goto _return_dev_put;
>
> We are after a succesful of_find_device_by_node and prior to 
> fman_bind(), mac_dev->fman_dev refcount is 1


Indeed. refcounts = 1.


>
>> @@ -213,40 +213,51 @@ static int mac_probe(struct platform_device 
>> *_of_dev)
>>       if (!priv->fman) {
>>           dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
>>           err = -ENODEV;
>> -        goto _return_of_node_put;
>> +        goto _return_dev_put;
>>       }


refcounts: 1 + 1 = 2.


>>   +    /* Two references have been taken in of_find_device_by_node()
>> +     * and fman_bind(). Release one of them here. The second one
>> +     * will be released in mac_remove().
>> +     */
>> +    put_device(mac_dev->fman_dev);


refcounts: 2 - 1 = 1.


>>       of_node_put(dev_node);
>> +    dev_node = NULL;
>>         /* Get the address of the memory mapped registers */
>>       mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
>>       if (!mac_dev->res) {
>>           dev_err(dev, "could not get registers\n");
>> -        return -EINVAL;
>> +        err = -EINVAL;
>> +        goto _return_dev_put;
>
> Here we are after a successful fman_bind(), mac_dev->fman_dev refcount 
> is 2. _return_dev_put will drop a single reference, this error path 
> looks buggy.


We released 1 reference above with "put_device(mac_dev->fman_dev);".


>
> Similar issue for the _return_dev_arr_put error path below.


Similar situation: we release 1 reference with 
"put_device(mac_dev->fman_port_devs[i]);".


>
> Cheers,
>
> Paolo
>
-- 
Kind regards
Aleksandr


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices
  2024-10-15  6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
  2024-10-15  6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
  2024-10-15  6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
@ 2024-10-21  9:20 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 6+ messages in thread
From: patchwork-bot+netdevbpf @ 2024-10-21  9:20 UTC (permalink / raw)
  To: Aleksandr Mishin
  Cc: igal.liberman, horms, madalin.bucur, sean.anderson, davem,
	edumazet, kuba, pabeni, netdev, linux-kernel, lvc-project

Hello:

This series was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:

On Tue, 15 Oct 2024 09:01:20 +0300 you wrote:
> The series is intended to fix refcount handling for fman-related "struct
> device" objects - the devices are not released upon driver removal or in
> the error paths during probe. This leads to device reference leaks.
> 
> The device pointers are now saved to struct mac_device and properly handled
> in the driver's probe and removal functions.
> 
> [...]

Here is the summary with links:
  - [net,1/2] fsl/fman: Save device references taken in mac_probe()
    https://git.kernel.org/netdev/net/c/efeddd552ec6
  - [net,2/2] fsl/fman: Fix refcount handling of fman-related devices
    https://git.kernel.org/netdev/net/c/1dec67e0d9fb

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-10-21  9:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-15  6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
2024-10-15  6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
2024-10-15  6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
2024-10-17 10:01   ` Paolo Abeni
2024-10-17 10:53     ` Aleksandr Mishin
2024-10-21  9:20 ` [PATCH net 0/2] " patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®