mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
Merge branch 'pci/controller/plda-host'
- Fix event IRQ user-after-free issues (Ali Tariq) - Fix IRQ domain leaks in error paths (Ali Tariq) * pci/controller/plda-host: PCI: plda: Fix IRQ domain leaks in the error paths of plda_init_interrupts() PCI: plda: Fix use-after-free of event IRQs during teardown
This commit is contained in:
@@ -419,6 +419,8 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
|
||||
return plda_allocate_msi_domains(port);
|
||||
}
|
||||
|
||||
static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie);
|
||||
|
||||
int plda_init_interrupts(struct platform_device *pdev,
|
||||
struct plda_pcie_rp *port,
|
||||
const struct plda_event *event)
|
||||
@@ -440,14 +442,17 @@ int plda_init_interrupts(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
port->irq = platform_get_irq(pdev, 0);
|
||||
if (port->irq < 0)
|
||||
return -ENODEV;
|
||||
if (port->irq < 0) {
|
||||
ret = -ENODEV;
|
||||
goto err_irq_domain_deinit;
|
||||
}
|
||||
|
||||
for_each_set_bit(i, &port->events_bitmap, port->num_events) {
|
||||
event_irq = irq_create_mapping(port->event_domain, i);
|
||||
if (!event_irq) {
|
||||
dev_err(dev, "failed to map hwirq %d\n", i);
|
||||
return -ENXIO;
|
||||
ret = -ENXIO;
|
||||
goto err_irq_domain_deinit;
|
||||
}
|
||||
|
||||
if (event->request_event_irq)
|
||||
@@ -459,7 +464,7 @@ int plda_init_interrupts(struct platform_device *pdev,
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request IRQ %d\n", event_irq);
|
||||
return ret;
|
||||
goto err_irq_domain_deinit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,7 +472,8 @@ int plda_init_interrupts(struct platform_device *pdev,
|
||||
event->intx_event);
|
||||
if (!port->intx_irq) {
|
||||
dev_err(dev, "failed to map INTx interrupt\n");
|
||||
return -ENXIO;
|
||||
ret = -ENXIO;
|
||||
goto err_irq_domain_deinit;
|
||||
}
|
||||
|
||||
/* Plug the INTx chained handler */
|
||||
@@ -475,8 +481,11 @@ int plda_init_interrupts(struct platform_device *pdev,
|
||||
|
||||
port->msi_irq = irq_create_mapping(port->event_domain,
|
||||
event->msi_event);
|
||||
if (!port->msi_irq)
|
||||
return -ENXIO;
|
||||
if (!port->msi_irq) {
|
||||
dev_err(dev, "failed to map MSI interrupt\n");
|
||||
ret = -ENXIO;
|
||||
goto err_irq_domain_deinit;
|
||||
}
|
||||
|
||||
/* Plug the MSI chained handler */
|
||||
irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port);
|
||||
@@ -485,6 +494,11 @@ int plda_init_interrupts(struct platform_device *pdev,
|
||||
irq_set_chained_handler_and_data(port->irq, plda_handle_event, port);
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq_domain_deinit:
|
||||
plda_pcie_irq_domain_deinit(port);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(plda_init_interrupts);
|
||||
|
||||
@@ -559,9 +573,27 @@ EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
|
||||
|
||||
static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
|
||||
{
|
||||
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
|
||||
irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
|
||||
irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
|
||||
u32 i, event_irq;
|
||||
|
||||
if (pcie->irq > 0)
|
||||
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
|
||||
if (pcie->msi_irq > 0)
|
||||
irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
|
||||
if (pcie->intx_irq > 0)
|
||||
irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
|
||||
|
||||
for_each_set_bit(i, &pcie->events_bitmap, pcie->num_events) {
|
||||
event_irq = irq_find_mapping(pcie->event_domain, i);
|
||||
if (event_irq) {
|
||||
devm_free_irq(pcie->dev, event_irq, pcie);
|
||||
irq_dispose_mapping(event_irq);
|
||||
}
|
||||
}
|
||||
|
||||
if (pcie->intx_irq)
|
||||
irq_dispose_mapping(pcie->intx_irq);
|
||||
if (pcie->msi_irq)
|
||||
irq_dispose_mapping(pcie->msi_irq);
|
||||
|
||||
irq_domain_remove(pcie->msi.dev_domain);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user