]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: dsa: bcm_sf2: Fix possible memory leak in bcm_sf2_mdio_register()
authorJinjie Ruan <ruanjinjie@huawei.com>
Wed, 11 Oct 2023 03:24:19 +0000 (11:24 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Oct 2023 09:58:57 +0000 (11:58 +0200)
commit 61b40cefe51af005c72dbdcf975a3d166c6e6406 upstream.

In bcm_sf2_mdio_register(), the class_find_device() will call get_device()
to increment reference count for priv->master_mii_bus->dev if
of_mdio_find_bus() succeeds. If mdiobus_alloc() or mdiobus_register()
fails, it will call get_device() twice without decrement reference count
for the device. And it is the same if bcm_sf2_mdio_register() succeeds but
fails in bcm_sf2_sw_probe(), or if bcm_sf2_sw_probe() succeeds. If the
reference count has not decremented to zero, the dev related resource will
not be freed.

So remove the get_device() in bcm_sf2_mdio_register(), and call
put_device() if mdiobus_alloc() or mdiobus_register() fails and in
bcm_sf2_mdio_unregister() to solve the issue.

And as Simon suggested, unwind from errors for bcm_sf2_mdio_register() and
just return 0 if it succeeds to make it cleaner.

Fixes: 461cd1b03e32 ("net: dsa: bcm_sf2: Register our slave MDIO bus")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Suggested-by: Simon Horman <horms@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Link: https://lore.kernel.org/r/20231011032419.2423290-1-ruanjinjie@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/dsa/bcm_sf2.c

index 773d751ef169f4f4a2c235a51b1ea40c01819f49..1fa392aee52de03ace28bc26120ac6b0dada8129 100644 (file)
@@ -577,17 +577,16 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
        priv->master_mii_bus = of_mdio_find_bus(dn);
        if (!priv->master_mii_bus) {
-               of_node_put(dn);
-               return -EPROBE_DEFER;
+               err = -EPROBE_DEFER;
+               goto err_of_node_put;
        }
 
-       get_device(&priv->master_mii_bus->dev);
        priv->master_mii_dn = dn;
 
        priv->slave_mii_bus = mdiobus_alloc();
        if (!priv->slave_mii_bus) {
-               of_node_put(dn);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_put_master_mii_bus_dev;
        }
 
        priv->slave_mii_bus->priv = priv;
@@ -644,11 +643,17 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        }
 
        err = mdiobus_register(priv->slave_mii_bus);
-       if (err && dn) {
-               mdiobus_free(priv->slave_mii_bus);
-               of_node_put(dn);
-       }
+       if (err && dn)
+               goto err_free_slave_mii_bus;
 
+       return 0;
+
+err_free_slave_mii_bus:
+       mdiobus_free(priv->slave_mii_bus);
+err_put_master_mii_bus_dev:
+       put_device(&priv->master_mii_bus->dev);
+err_of_node_put:
+       of_node_put(dn);
        return err;
 }
 
@@ -656,6 +661,7 @@ static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
 {
        mdiobus_unregister(priv->slave_mii_bus);
        mdiobus_free(priv->slave_mii_bus);
+       put_device(&priv->master_mii_bus->dev);
        of_node_put(priv->master_mii_dn);
 }