PCI: tegra: Fix OF node reference leak
authorNishka Dasgupta <nishkadg.linux@gmail.com>
Wed, 24 Jul 2019 08:24:12 +0000 (13:54 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 7 Oct 2019 16:53:16 +0000 (18:53 +0200)
[ Upstream commit 9e38e690ace3e7a22a81fc02652fc101efb340cf ]

Each iteration of for_each_child_of_node() executes of_node_put() on the
previous node, but in some return paths in the middle of the loop
of_node_put() is missing thus causing a reference leak.

Hence stash these mid-loop return values in a variable 'err' and add a
new label err_node_put which executes of_node_put() on the previous node
and returns 'err' on failure.

Change mid-loop return statements to point to jump to this label to
fix the reference leak.

Issue found with Coccinelle.

Signed-off-by: Nishka Dasgupta <nishkadg.linux@gmail.com>
[lorenzo.pieralisi@arm.com: rewrote commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/pci/host/pci-tegra.c

index 8dfccf7..8e101b1 100644 (file)
@@ -1898,14 +1898,15 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
                err = of_pci_get_devfn(port);
                if (err < 0) {
                        dev_err(dev, "failed to parse address: %d\n", err);
-                       return err;
+                       goto err_node_put;
                }
 
                index = PCI_SLOT(err);
 
                if (index < 1 || index > soc->num_ports) {
                        dev_err(dev, "invalid port number: %d\n", index);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto err_node_put;
                }
 
                index--;
@@ -1914,12 +1915,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
                if (err < 0) {
                        dev_err(dev, "failed to parse # of lanes: %d\n",
                                err);
-                       return err;
+                       goto err_node_put;
                }
 
                if (value > 16) {
                        dev_err(dev, "invalid # of lanes: %u\n", value);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto err_node_put;
                }
 
                lanes |= value << (index << 3);
@@ -1933,13 +1935,15 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
                lane += value;
 
                rp = devm_kzalloc(dev, sizeof(*rp), GFP_KERNEL);
-               if (!rp)
-                       return -ENOMEM;
+               if (!rp) {
+                       err = -ENOMEM;
+                       goto err_node_put;
+               }
 
                err = of_address_to_resource(port, 0, &rp->regs);
                if (err < 0) {
                        dev_err(dev, "failed to parse address: %d\n", err);
-                       return err;
+                       goto err_node_put;
                }
 
                INIT_LIST_HEAD(&rp->list);
@@ -1966,6 +1970,10 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
                return err;
 
        return 0;
+
+err_node_put:
+       of_node_put(port);
+       return err;
 }
 
 /*