Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0571d23f authored by Tong Zhang's avatar Tong Zhang Committed by Greg Kroah-Hartman
Browse files

net: arcnet: com20020 fix error handling



[ Upstream commit 6577b9a551aedb86bca6d4438c28386361845108 ]

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: default avatarTong Zhang <ztong0001@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Stable-dep-of: 6b17a597fc2f ("arcnet: restoring support for multiple Sohard Arcnet cards")
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent eea423aa
Loading
Loading
Loading
Loading
+19 −15
Original line number Diff line number Diff line
@@ -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;

@@ -142,6 +144,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) {
@@ -164,7 +168,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;

@@ -181,7 +185,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
@@ -219,18 +223,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;
@@ -256,28 +260,28 @@ 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);
	}

	pci_set_drvdata(pdev, priv);

	return 0;
		continue;

out_port:
err_free_arcdev:
		free_arcdev(dev);
		break;
	}
	if (ret)
		com20020pci_remove(pdev);
	return ret;
}