diff options
author | Thomas Chou <thomas@wytron.com.tw> | 2010-05-23 12:44:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-24 02:11:09 -0400 |
commit | ee02a4ef40f2e049c80f9cc04e21a9b48288b6ff (patch) | |
tree | 26a6accadf8b370425b7c7c5e15351375a1fbf10 /drivers | |
parent | 253683bbfb6bc5864417c8c35cb6ef13b5e259e6 (diff) |
ethoc: fix null dereference in ethoc_probe
Dan reported the patch 0baa080c75c: "ethoc: use system memory
as buffer" introduced a potential null dereference.
1060 free:
1061 if (priv->dma_alloc)
^^^^^^^^^^^^^^^
priv can be null here.
He also suggested that the error handling is not complete.
This patch fixes the null priv issue and improves resources
releasing in ethoc_probe() and ethoc_remove().
Reported-by: Dan Carpenter <error27@gmail.com>
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethoc.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 14cbde5cf68e..6ed2df14ec84 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c | |||
@@ -174,6 +174,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); | |||
174 | * @iobase: pointer to I/O memory region | 174 | * @iobase: pointer to I/O memory region |
175 | * @membase: pointer to buffer memory region | 175 | * @membase: pointer to buffer memory region |
176 | * @dma_alloc: dma allocated buffer size | 176 | * @dma_alloc: dma allocated buffer size |
177 | * @io_region_size: I/O memory region size | ||
177 | * @num_tx: number of send buffers | 178 | * @num_tx: number of send buffers |
178 | * @cur_tx: last send buffer written | 179 | * @cur_tx: last send buffer written |
179 | * @dty_tx: last buffer actually sent | 180 | * @dty_tx: last buffer actually sent |
@@ -193,6 +194,7 @@ struct ethoc { | |||
193 | void __iomem *iobase; | 194 | void __iomem *iobase; |
194 | void __iomem *membase; | 195 | void __iomem *membase; |
195 | int dma_alloc; | 196 | int dma_alloc; |
197 | resource_size_t io_region_size; | ||
196 | 198 | ||
197 | unsigned int num_tx; | 199 | unsigned int num_tx; |
198 | unsigned int cur_tx; | 200 | unsigned int cur_tx; |
@@ -943,6 +945,7 @@ static int ethoc_probe(struct platform_device *pdev) | |||
943 | priv = netdev_priv(netdev); | 945 | priv = netdev_priv(netdev); |
944 | priv->netdev = netdev; | 946 | priv->netdev = netdev; |
945 | priv->dma_alloc = 0; | 947 | priv->dma_alloc = 0; |
948 | priv->io_region_size = mmio->end - mmio->start + 1; | ||
946 | 949 | ||
947 | priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, | 950 | priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, |
948 | resource_size(mmio)); | 951 | resource_size(mmio)); |
@@ -1047,20 +1050,34 @@ static int ethoc_probe(struct platform_device *pdev) | |||
1047 | ret = register_netdev(netdev); | 1050 | ret = register_netdev(netdev); |
1048 | if (ret < 0) { | 1051 | if (ret < 0) { |
1049 | dev_err(&netdev->dev, "failed to register interface\n"); | 1052 | dev_err(&netdev->dev, "failed to register interface\n"); |
1050 | goto error; | 1053 | goto error2; |
1051 | } | 1054 | } |
1052 | 1055 | ||
1053 | goto out; | 1056 | goto out; |
1054 | 1057 | ||
1058 | error2: | ||
1059 | netif_napi_del(&priv->napi); | ||
1055 | error: | 1060 | error: |
1056 | mdiobus_unregister(priv->mdio); | 1061 | mdiobus_unregister(priv->mdio); |
1057 | free_mdio: | 1062 | free_mdio: |
1058 | kfree(priv->mdio->irq); | 1063 | kfree(priv->mdio->irq); |
1059 | mdiobus_free(priv->mdio); | 1064 | mdiobus_free(priv->mdio); |
1060 | free: | 1065 | free: |
1061 | if (priv->dma_alloc) | 1066 | if (priv) { |
1062 | dma_free_coherent(NULL, priv->dma_alloc, priv->membase, | 1067 | if (priv->dma_alloc) |
1063 | netdev->mem_start); | 1068 | dma_free_coherent(NULL, priv->dma_alloc, priv->membase, |
1069 | netdev->mem_start); | ||
1070 | else if (priv->membase) | ||
1071 | devm_iounmap(&pdev->dev, priv->membase); | ||
1072 | if (priv->iobase) | ||
1073 | devm_iounmap(&pdev->dev, priv->iobase); | ||
1074 | } | ||
1075 | if (mem) | ||
1076 | devm_release_mem_region(&pdev->dev, mem->start, | ||
1077 | mem->end - mem->start + 1); | ||
1078 | if (mmio) | ||
1079 | devm_release_mem_region(&pdev->dev, mmio->start, | ||
1080 | mmio->end - mmio->start + 1); | ||
1064 | free_netdev(netdev); | 1081 | free_netdev(netdev); |
1065 | out: | 1082 | out: |
1066 | return ret; | 1083 | return ret; |
@@ -1078,6 +1095,7 @@ static int ethoc_remove(struct platform_device *pdev) | |||
1078 | platform_set_drvdata(pdev, NULL); | 1095 | platform_set_drvdata(pdev, NULL); |
1079 | 1096 | ||
1080 | if (netdev) { | 1097 | if (netdev) { |
1098 | netif_napi_del(&priv->napi); | ||
1081 | phy_disconnect(priv->phy); | 1099 | phy_disconnect(priv->phy); |
1082 | priv->phy = NULL; | 1100 | priv->phy = NULL; |
1083 | 1101 | ||
@@ -1089,6 +1107,14 @@ static int ethoc_remove(struct platform_device *pdev) | |||
1089 | if (priv->dma_alloc) | 1107 | if (priv->dma_alloc) |
1090 | dma_free_coherent(NULL, priv->dma_alloc, priv->membase, | 1108 | dma_free_coherent(NULL, priv->dma_alloc, priv->membase, |
1091 | netdev->mem_start); | 1109 | netdev->mem_start); |
1110 | else { | ||
1111 | devm_iounmap(&pdev->dev, priv->membase); | ||
1112 | devm_release_mem_region(&pdev->dev, netdev->mem_start, | ||
1113 | netdev->mem_end - netdev->mem_start + 1); | ||
1114 | } | ||
1115 | devm_iounmap(&pdev->dev, priv->iobase); | ||
1116 | devm_release_mem_region(&pdev->dev, netdev->base_addr, | ||
1117 | priv->io_region_size); | ||
1092 | unregister_netdev(netdev); | 1118 | unregister_netdev(netdev); |
1093 | free_netdev(netdev); | 1119 | free_netdev(netdev); |
1094 | } | 1120 | } |