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

Commit d2b2159b authored by Dongliang Mu's avatar Dongliang Mu Committed by Sasha Levin
Browse files

ipack: tpci200: fix many double free issues in tpci200_pci_probe



[ Upstream commit 57a1681095f912239c7fb4d66683ab0425973838 ]

The function tpci200_register called by tpci200_install and
tpci200_unregister called by tpci200_uninstall are in pair. However,
tpci200_unregister has some cleanup operations not in the
tpci200_register. So the error handling code of tpci200_pci_probe has
many different double free issues.

Fix this problem by moving those cleanup operations out of
tpci200_unregister, into tpci200_pci_remove and reverting
the previous commit 9272e5d0028d ("ipack/carriers/tpci200:
Fix a double free in tpci200_pci_probe").

Fixes: 9272e5d0028d ("ipack/carriers/tpci200: Fix a double free in tpci200_pci_probe")
Cc: stable@vger.kernel.org
Reported-by: default avatarDongliang Mu <mudongliangabcd@gmail.com>
Signed-off-by: default avatarDongliang Mu <mudongliangabcd@gmail.com>
Link: https://lore.kernel.org/r/20210810100323.3938492-1-mudongliangabcd@gmail.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 591bf123
Loading
Loading
Loading
Loading
+18 −18
Original line number Original line Diff line number Diff line
@@ -94,16 +94,13 @@ static void tpci200_unregister(struct tpci200_board *tpci200)
	free_irq(tpci200->info->pdev->irq, (void *) tpci200);
	free_irq(tpci200->info->pdev->irq, (void *) tpci200);


	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);


	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);


	pci_disable_device(tpci200->info->pdev);
	pci_disable_device(tpci200->info->pdev);
	pci_dev_put(tpci200->info->pdev);
}
}


static void tpci200_enable_irq(struct tpci200_board *tpci200,
static void tpci200_enable_irq(struct tpci200_board *tpci200,
@@ -524,7 +521,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
	tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
	tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
	if (!tpci200->info) {
	if (!tpci200->info) {
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto out_err_info;
		goto err_tpci200;
	}
	}


	pci_dev_get(pdev);
	pci_dev_get(pdev);
@@ -535,7 +532,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
	if (ret) {
	if (ret) {
		dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory");
		dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory");
		ret = -EBUSY;
		ret = -EBUSY;
		goto out_err_pci_request;
		goto err_tpci200_info;
	}
	}
	tpci200->info->cfg_regs = ioremap_nocache(
	tpci200->info->cfg_regs = ioremap_nocache(
			pci_resource_start(pdev, TPCI200_CFG_MEM_BAR),
			pci_resource_start(pdev, TPCI200_CFG_MEM_BAR),
@@ -543,7 +540,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
	if (!tpci200->info->cfg_regs) {
	if (!tpci200->info->cfg_regs) {
		dev_err(&pdev->dev, "Failed to map PCI Configuration Memory");
		dev_err(&pdev->dev, "Failed to map PCI Configuration Memory");
		ret = -EFAULT;
		ret = -EFAULT;
		goto out_err_ioremap;
		goto err_request_region;
	}
	}


	/* Disable byte swapping for 16 bit IP module access. This will ensure
	/* Disable byte swapping for 16 bit IP module access. This will ensure
@@ -566,7 +563,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
	if (ret) {
	if (ret) {
		dev_err(&pdev->dev, "error during tpci200 install\n");
		dev_err(&pdev->dev, "error during tpci200 install\n");
		ret = -ENODEV;
		ret = -ENODEV;
		goto out_err_install;
		goto err_cfg_regs;
	}
	}


	/* Register the carrier in the industry pack bus driver */
	/* Register the carrier in the industry pack bus driver */
@@ -578,7 +575,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
		dev_err(&pdev->dev,
		dev_err(&pdev->dev,
			"error registering the carrier on ipack driver\n");
			"error registering the carrier on ipack driver\n");
		ret = -EFAULT;
		ret = -EFAULT;
		goto out_err_bus_register;
		goto err_tpci200_install;
	}
	}


	/* save the bus number given by ipack to logging purpose */
	/* save the bus number given by ipack to logging purpose */
@@ -589,19 +586,16 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
		tpci200_create_device(tpci200, i);
		tpci200_create_device(tpci200, i);
	return 0;
	return 0;


out_err_bus_register:
err_tpci200_install:
	tpci200_uninstall(tpci200);
	tpci200_uninstall(tpci200);
	/* tpci200->info->cfg_regs is unmapped in tpci200_uninstall */
err_cfg_regs:
	tpci200->info->cfg_regs = NULL;
	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);
out_err_install:
err_request_region:
	if (tpci200->info->cfg_regs)
		iounmap(tpci200->info->cfg_regs);
out_err_ioremap:
	pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
	pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
out_err_pci_request:
err_tpci200_info:
	pci_dev_put(pdev);
	kfree(tpci200->info);
	kfree(tpci200->info);
out_err_info:
	pci_dev_put(pdev);
err_tpci200:
	kfree(tpci200);
	kfree(tpci200);
	return ret;
	return ret;
}
}
@@ -611,6 +605,12 @@ static void __tpci200_pci_remove(struct tpci200_board *tpci200)
	ipack_bus_unregister(tpci200->info->ipack_bus);
	ipack_bus_unregister(tpci200->info->ipack_bus);
	tpci200_uninstall(tpci200);
	tpci200_uninstall(tpci200);


	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);

	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);

	pci_dev_put(tpci200->info->pdev);

	kfree(tpci200->info);
	kfree(tpci200->info);
	kfree(tpci200);
	kfree(tpci200);
}
}