[PATCH net] net: ethernet: sunplus: spl2sw: fix multiple of_node refcount leaks in probe

Shitalkumar Gandhi posted 1 patch 7 hours ago
drivers/net/ethernet/sunplus/spl2sw_driver.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
[PATCH net] net: ethernet: sunplus: spl2sw: fix multiple of_node refcount leaks in probe
Posted by Shitalkumar Gandhi 7 hours ago
spl2sw_probe() acquires three of_node references that are never properly
released in all paths:

  - eth_ports_np from of_get_child_by_name() leaks on every probe.
  - port_np returned from spl2sw_get_eth_child_node() (which exits a
    for_each_child_of_node() loop mid-iteration) leaks per loop pass.
  - phy_np from of_parse_phandle() leaks on the -EPROBE_DEFER and
    spl2sw_init_netdev() failure goto paths, and the registered netdev's
    mac->phy_node is not released on the out_unregister_dev cleanup path.

Convert eth_ports_np and port_np to scoped __free(device_node), add
explicit of_node_put(phy_np) on the two early-error gotos where
ownership has not yet been transferred to mac->phy_node, and release
each registered ndev's mac->phy_node in the out_unregister_dev loop
before unregister_netdev().

The mac->phy_node release in the normal driver-remove path is handled
by the preceding fix to spl2sw_phy_remove().

Fixes: fd3040b9394c ("net: ethernet: Add driver for Sunplus SP7021")
Cc: stable@vger.kernel.org
Signed-off-by: Shitalkumar Gandhi <shitalkumar.gandhi@cambiumnetworks.com>
---
 drivers/net/ethernet/sunplus/spl2sw_driver.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/sunplus/spl2sw_driver.c b/drivers/net/ethernet/sunplus/spl2sw_driver.c
index 5e0e4c9ecbb0..d78bda050ee4 100644
--- a/drivers/net/ethernet/sunplus/spl2sw_driver.c
+++ b/drivers/net/ethernet/sunplus/spl2sw_driver.c
@@ -319,10 +319,8 @@ static struct device_node *spl2sw_get_eth_child_node(struct device_node *ether_n
 
 static int spl2sw_probe(struct platform_device *pdev)
 {
-	struct device_node *eth_ports_np;
-	struct device_node *port_np;
+	struct device_node *eth_ports_np __free(device_node) = NULL;
 	struct spl2sw_common *comm;
-	struct device_node *phy_np;
 	phy_interface_t phy_mode;
 	struct net_device *ndev;
 	struct spl2sw_mac *mac;
@@ -418,8 +416,10 @@ static int spl2sw_probe(struct platform_device *pdev)
 	}
 
 	for (i = 0; i < MAX_NETDEV_NUM; i++) {
-		/* Get port@i of node ethernet-ports. */
-		port_np = spl2sw_get_eth_child_node(eth_ports_np, i);
+		struct device_node *port_np __free(device_node) =
+			spl2sw_get_eth_child_node(eth_ports_np, i);
+		struct device_node *phy_np;
+
 		if (!port_np)
 			continue;
 
@@ -441,6 +441,7 @@ static int spl2sw_probe(struct platform_device *pdev)
 		/* Get mac-address from nvmem. */
 		ret = spl2sw_nvmem_get_mac_address(&pdev->dev, port_np, mac_addr);
 		if (ret == -EPROBE_DEFER) {
+			of_node_put(phy_np);
 			goto out_unregister_dev;
 		} else if (ret) {
 			dev_info(&pdev->dev, "Generate a random mac address!\n");
@@ -449,8 +450,10 @@ static int spl2sw_probe(struct platform_device *pdev)
 
 		/* Initialize the net device. */
 		ret = spl2sw_init_netdev(pdev, mac_addr, &ndev);
-		if (ret)
+		if (ret) {
+			of_node_put(phy_np);
 			goto out_unregister_dev;
+		}
 
 		ndev->irq = irq;
 		comm->ndev[i] = ndev;
@@ -500,8 +503,11 @@ static int spl2sw_probe(struct platform_device *pdev)
 
 out_unregister_dev:
 	for (i = 0; i < MAX_NETDEV_NUM; i++)
-		if (comm->ndev[i])
+		if (comm->ndev[i]) {
+			mac = netdev_priv(comm->ndev[i]);
+			of_node_put(mac->phy_node);
 			unregister_netdev(comm->ndev[i]);
+		}
 
 out_free_mdio:
 	spl2sw_mdio_remove(comm);
-- 
2.25.1