[PATCH] can: sja1000: kvaser_pci: fix duplicate PCI I/O unmapping

Guangshuo Li posted 1 patch 1 week, 2 days ago
drivers/net/can/sja1000/kvaser_pci.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
[PATCH] can: sja1000: kvaser_pci: fix duplicate PCI I/O unmapping
Posted by Guangshuo Li 1 week, 2 days ago
kvaser_pci_init_one() maps the PCI I/O regions with pci_iomap(), while
kvaser_pci_del_chan() also unmaps the same mappings as part of channel
cleanup.

If kvaser_pci_add_chan() fails after the master device has been
initialized, the probe error path calls kvaser_pci_del_chan(), which
unmaps the PCI I/O regions, and then falls through to failure_iounmap,
where the same mappings are unmapped again.

Move the PCI I/O unmapping out of kvaser_pci_del_chan(). Let the probe
error path release the mappings through failure_iounmap and explicitly
release them in kvaser_pci_remove_one() after channel cleanup. This
ensures that each PCI I/O mapping is released exactly once.

This issue was found by manual code inspection.

Fixes: 3878fb6fdbce ("The patch adds support for the PCI cards: PCIcan and PCIcanx (1, 2 or 4 channel) from Kvaser (http://www.kvaser.com).")
Cc: stable@vger.kernel.org
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
 drivers/net/can/sja1000/kvaser_pci.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c
index 95fe9ee1ce32..b21ca65d2daa 100644
--- a/drivers/net/can/sja1000/kvaser_pci.c
+++ b/drivers/net/can/sja1000/kvaser_pci.c
@@ -186,10 +186,6 @@ static void kvaser_pci_del_chan(struct net_device *dev)
 	}
 	unregister_sja1000dev(dev);
 
-	pci_iounmap(board->pci_dev, priv->reg_base);
-	pci_iounmap(board->pci_dev, board->conf_addr);
-	pci_iounmap(board->pci_dev, board->res_addr);
-
 	free_sja1000dev(dev);
 }
 
@@ -367,9 +363,18 @@ static int kvaser_pci_init_one(struct pci_dev *pdev,
 static void kvaser_pci_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct sja1000_priv *priv = netdev_priv(dev);
+	struct kvaser_pci *board = priv->priv;
+	void __iomem *base_addr = priv->reg_base;
+	void __iomem *conf_addr = board->conf_addr;
+	void __iomem *res_addr = board->res_addr;
 
 	kvaser_pci_del_chan(dev);
 
+	pci_iounmap(pdev, conf_addr);
+	pci_iounmap(pdev, res_addr);
+	pci_iounmap(pdev, base_addr);
+
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
-- 
2.43.0