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 | |
| 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>
| -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 | } |
