net: arcnet: com20020 fix error handling
There are two issues when handling error case in com20020pci_probe() 1. priv might be not initialized yet when calling com20020pci_remove() from com20020pci_probe(), since the priv is set at the very last but it can jump to error handling in the middle and priv remains NULL. 2. memory leak - the net device is allocated in alloc_arcdev but not properly released if error happens in the middle of the big for loop [ 1.529110] BUG: kernel NULL pointer dereference, address: 0000000000000008 [ 1.531447] RIP: 0010:com20020pci_remove+0x15/0x60 [com20020_pci] [ 1.536805] Call Trace: [ 1.536939] com20020pci_probe+0x3f2/0x48c [com20020_pci] [ 1.537226] local_pci_probe+0x48/0x80 [ 1.539918] com20020pci_init+0x3f/0x1000 [com20020_pci] Signed-off-by: Tong Zhang <ztong0001@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
ad236ccde1
Коммит
6577b9a551
|
@ -127,6 +127,8 @@ static int com20020pci_probe(struct pci_dev *pdev,
|
|||
int i, ioaddr, ret;
|
||||
struct resource *r;
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
return -EIO;
|
||||
|
||||
|
@ -139,6 +141,8 @@ static int com20020pci_probe(struct pci_dev *pdev,
|
|||
priv->ci = ci;
|
||||
mm = &ci->misc_map;
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
|
||||
INIT_LIST_HEAD(&priv->list_dev);
|
||||
|
||||
if (mm->size) {
|
||||
|
@ -161,7 +165,7 @@ static int com20020pci_probe(struct pci_dev *pdev,
|
|||
dev = alloc_arcdev(device);
|
||||
if (!dev) {
|
||||
ret = -ENOMEM;
|
||||
goto out_port;
|
||||
break;
|
||||
}
|
||||
dev->dev_port = i;
|
||||
|
||||
|
@ -178,7 +182,7 @@ static int com20020pci_probe(struct pci_dev *pdev,
|
|||
pr_err("IO region %xh-%xh already allocated\n",
|
||||
ioaddr, ioaddr + cm->size - 1);
|
||||
ret = -EBUSY;
|
||||
goto out_port;
|
||||
goto err_free_arcdev;
|
||||
}
|
||||
|
||||
/* Dummy access after Reset
|
||||
|
@ -216,18 +220,18 @@ static int com20020pci_probe(struct pci_dev *pdev,
|
|||
if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
|
||||
pr_err("IO address %Xh is empty!\n", ioaddr);
|
||||
ret = -EIO;
|
||||
goto out_port;
|
||||
goto err_free_arcdev;
|
||||
}
|
||||
if (com20020_check(dev)) {
|
||||
ret = -EIO;
|
||||
goto out_port;
|
||||
goto err_free_arcdev;
|
||||
}
|
||||
|
||||
card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
|
||||
GFP_KERNEL);
|
||||
if (!card) {
|
||||
ret = -ENOMEM;
|
||||
goto out_port;
|
||||
goto err_free_arcdev;
|
||||
}
|
||||
|
||||
card->index = i;
|
||||
|
@ -253,29 +257,29 @@ static int com20020pci_probe(struct pci_dev *pdev,
|
|||
|
||||
ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
|
||||
if (ret)
|
||||
goto out_port;
|
||||
goto err_free_arcdev;
|
||||
|
||||
ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
|
||||
if (ret)
|
||||
goto out_port;
|
||||
goto err_free_arcdev;
|
||||
|
||||
dev_set_drvdata(&dev->dev, card);
|
||||
|
||||
ret = com20020_found(dev, IRQF_SHARED);
|
||||
if (ret)
|
||||
goto out_port;
|
||||
goto err_free_arcdev;
|
||||
|
||||
devm_arcnet_led_init(dev, dev->dev_id, i);
|
||||
|
||||
list_add(&card->list, &priv->list_dev);
|
||||
continue;
|
||||
|
||||
err_free_arcdev:
|
||||
free_arcdev(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
|
||||
out_port:
|
||||
com20020pci_remove(pdev);
|
||||
if (ret)
|
||||
com20020pci_remove(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче