]>
Commit | Line | Data |
---|---|---|
745b9103 GKH |
1 | From foo@baz Wed Apr 29 12:00:18 CEST 2015 |
2 | From: Alexey Khoroshilov <khoroshilov@ispras.ru> | |
3 | Date: Sat, 25 Apr 2015 04:07:03 +0300 | |
4 | Subject: pxa168: fix double deallocation of managed resources | |
5 | ||
6 | From: Alexey Khoroshilov <khoroshilov@ispras.ru> | |
7 | ||
8 | [ Upstream commit 0e03fd3e335d272bee88fe733d5fd13f5c5b7140 ] | |
9 | ||
10 | Commit 43d3ddf87a57 ("net: pxa168_eth: add device tree support") starts | |
11 | to use managed resources by adding devm_clk_get() and | |
12 | devm_ioremap_resource(), but it leaves explicit iounmap() and clock_put() | |
13 | in pxa168_eth_remove() and in failure handling code of pxa168_eth_probe(). | |
14 | As a result double free can happen. | |
15 | ||
16 | The patch removes explicit resource deallocation. Also it converts | |
17 | clk_disable() to clk_disable_unprepare() to make it symmetrical with | |
18 | clk_prepare_enable(). | |
19 | ||
20 | Found by Linux Driver Verification project (linuxtesting.org). | |
21 | ||
22 | Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> | |
23 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
24 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
25 | --- | |
26 | drivers/net/ethernet/marvell/pxa168_eth.c | 16 +++++----------- | |
27 | 1 file changed, 5 insertions(+), 11 deletions(-) | |
28 | ||
29 | --- a/drivers/net/ethernet/marvell/pxa168_eth.c | |
30 | +++ b/drivers/net/ethernet/marvell/pxa168_eth.c | |
31 | @@ -1508,7 +1508,8 @@ static int pxa168_eth_probe(struct platf | |
32 | np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); | |
33 | if (!np) { | |
34 | dev_err(&pdev->dev, "missing phy-handle\n"); | |
35 | - return -EINVAL; | |
36 | + err = -EINVAL; | |
37 | + goto err_netdev; | |
38 | } | |
39 | of_property_read_u32(np, "reg", &pep->phy_addr); | |
40 | pep->phy_intf = of_get_phy_mode(pdev->dev.of_node); | |
41 | @@ -1526,7 +1527,7 @@ static int pxa168_eth_probe(struct platf | |
42 | pep->smi_bus = mdiobus_alloc(); | |
43 | if (pep->smi_bus == NULL) { | |
44 | err = -ENOMEM; | |
45 | - goto err_base; | |
46 | + goto err_netdev; | |
47 | } | |
48 | pep->smi_bus->priv = pep; | |
49 | pep->smi_bus->name = "pxa168_eth smi"; | |
50 | @@ -1551,13 +1552,10 @@ err_mdiobus: | |
51 | mdiobus_unregister(pep->smi_bus); | |
52 | err_free_mdio: | |
53 | mdiobus_free(pep->smi_bus); | |
54 | -err_base: | |
55 | - iounmap(pep->base); | |
56 | err_netdev: | |
57 | free_netdev(dev); | |
58 | err_clk: | |
59 | - clk_disable(clk); | |
60 | - clk_put(clk); | |
61 | + clk_disable_unprepare(clk); | |
62 | return err; | |
63 | } | |
64 | ||
65 | @@ -1574,13 +1572,9 @@ static int pxa168_eth_remove(struct plat | |
66 | if (pep->phy) | |
67 | phy_disconnect(pep->phy); | |
68 | if (pep->clk) { | |
69 | - clk_disable(pep->clk); | |
70 | - clk_put(pep->clk); | |
71 | - pep->clk = NULL; | |
72 | + clk_disable_unprepare(pep->clk); | |
73 | } | |
74 | ||
75 | - iounmap(pep->base); | |
76 | - pep->base = NULL; | |
77 | mdiobus_unregister(pep->smi_bus); | |
78 | mdiobus_free(pep->smi_bus); | |
79 | unregister_netdev(dev); |