Linux PCI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ali Tariq" <alitariq45892@gmail.com>
Cc: linux-pci@vger.kernel.org
Subject: Re: [PATCH] PCI: plda: Fix use-after-free of event IRQs during teardown
Date: Sat, 18 Jul 2026 12:07:01 +0000	[thread overview]
Message-ID: <20260718120701.DF4111F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260718115022.231990-1-alitariq45892@gmail.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing `irq_dispose_mapping()` before removing IRQ domains causes descriptor leaks and triggers `WARN_ON`.
- [High] IRQ domains and mappings are permanently leaked if initialization fails in `plda_init_interrupts()`.
- [High] Partial domain creation failure leaks previously allocated domains in `plda_pcie_init_irq_domains()`.
- [High] Unregistering chained interrupt handlers without synchronization leads to Use-After-Free of IRQ domains.
- [Medium] Double registration of IRQ handlers for INTx and MSI events orphans devres actions.
--

--- Patch [1]: [PATCH] PCI: plda: Fix use-after-free of event IRQs during teardown ---
commit 9f5cef697b1d53b10380f6d82145d7cc265b3fb6
Author: Ali Tariq <alitariq45892@gmail.com>

PCI: plda: Fix use-after-free of event IRQs during teardown

plda_pcie_irq_domain_deinit() removes pcie->event_domain via
irq_domain_remove(), but the per-event IRQs mapped from that domain
are requested with devm_request_irq() in plda_init_interrupts(). The
actual free_irq() for a devm-managed IRQ is deferred by devres until
after the calling probe()/remove() function returns.
    
This means irq_domain_remove() can free the domain's internal data
before the deferred free_irq() for IRQs still mapped into it has run.
When devres later processes that deferred cleanup, it can end up
dereferencing the already-freed domain.

Free each event IRQ explicitly with devm_free_irq() before removing
the domain. This triggers the free immediately and removes the IRQ
from the devres tracking list, so devres will not attempt to free it
a second time later.

Link: https://lore.kernel.org/linux-pci/20260714115343.4D49E1F000E9@smtp.kernel.org/

> diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
> index f9a34f323ad8c..cda8fdb088fd6 100644
> --- a/drivers/pci/controller/plda/pcie-plda-host.c
> +++ b/drivers/pci/controller/plda/pcie-plda-host.c
> @@ -559,10 +559,18 @@ EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
>  
>  static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
>  {
> +	u32 i, event_irq;
> +
>  	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);

[Severity: High]
This isn't a bug introduced by this patch, but does clearing the chained
handlers without synchronization leave us exposed to a use-after-free?

Calling irq_set_chained_handler_and_data with NULL updates the flow
handler but doesn't wait for actively executing instances to complete.
Without an explicit synchronize_irq, a concurrent handler like
plda_handle_event could still be executing on another CPU. 

If we then proceed to destroy the domains with irq_domain_remove below,
the concurrent handler might dereference the freed domains. Should there
be a synchronize_irq call here?

> +	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_domain_remove(pcie->msi.dev_domain);
>  
>  	irq_domain_remove(pcie->intx_domain);
>  	irq_domain_remove(pcie->event_domain);

[Severity: High]
This is a pre-existing issue, but does removing these IRQ domains without
disposing their mappings cause descriptor leaks?

While this patch explicitly frees the IRQs via devm_free_irq, the
underlying virtual IRQs were created using irq_create_mapping but are
never disposed via irq_dispose_mapping.

Removing an IRQ domain with active mappings triggers a warning in the core
IRQ code. This permanently leaks the underlying Linux IRQ descriptors and
radix tree nodes. Should the mappings be disposed before removing the
domains?

>  }

[ ... ]

Additional pre-existing issues were found in the same file:

[Severity: High]
This is a pre-existing issue, but does an error in plda_init_interrupts
leak the IRQ domains and mappings?

In plda_pcie_host_init:

	ret = plda_init_interrupts(pdev, port, plda_event);
	if (ret)
		goto err_host;
...
err_probe:
	plda_pcie_irq_domain_deinit(port);
err_host:
	if (port->host_ops && port->host_ops->host_deinit)
		port->host_ops->host_deinit(port);

	return ret;

If plda_init_interrupts fails partway through, the goto err_host path
bypasses plda_pcie_irq_domain_deinit. Since the domains and mappings
allocated up to the failure point are never cleaned up, does this result
in a permanent resource leak?


[Severity: High]
This is a pre-existing issue, but does a partial allocation failure during
domain creation leak previously created domains?

In plda_pcie_init_irq_domains:

	port->event_domain = irq_domain_create_linear( ... );
	if (!port->event_domain) { ... }

	...

	port->intx_domain = irq_domain_create_linear( ... );
	if (!port->intx_domain) {
		dev_err(dev, "failed to get an INTx IRQ domain\n");
		of_node_put(pcie_intc_node);
		return -ENOMEM;
	}

If the intx_domain allocation fails, the function returns -ENOMEM without
destroying the successfully created port->event_domain. Similarly, if
plda_allocate_msi_domains fails later, neither domain is freed. 
Should this error path clean up the already-allocated domains?


[Severity: Medium]
This is a pre-existing issue, but does overwriting the flow handlers orphan
the previously registered actions?

In plda_init_interrupts:

	for_each_set_bit(i, &port->events_bitmap, port->num_events) {
		event_irq = irq_create_mapping(port->event_domain, i);
		...
			ret = devm_request_irq(dev, event_irq,
					       plda_event_handler,
					       0, NULL, port);
		...
	}

	port->intx_irq = irq_create_mapping(port->event_domain,
					    event->intx_event);
	...
	/* Plug the INTx chained handler */
	irq_set_chained_handler_and_data(port->intx_irq, plda_handle_intx, port);

The events_bitmap typically includes intx_event and msi_event. The loop
registers a threaded irqaction via devm_request_irq for these events.
Immediately after, irq_set_chained_handler_and_data overwrites the flow
handler for the exact same virtual IRQs.

By replacing the generic flow handler with a custom chained handler, the
original action registered by devm_request_irq is permanently bypassed
and orphaned. Does this needlessly consume memory and leave inactive actions
until teardown?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260718115022.231990-1-alitariq45892@gmail.com?part=1

      reply	other threads:[~2026-07-18 12:07 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-18 11:50 [PATCH] PCI: plda: Fix use-after-free of event IRQs during teardown Ali Tariq
2026-07-18 12:07 ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260718120701.DF4111F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=alitariq45892@gmail.com \
    --cc=linux-pci@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox