All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Logan Gunthorpe" <logang@deltatee.com>
Cc: vkoul@kernel.org, dmaengine@vger.kernel.org, Frank.Li@kernel.org,
	linux-pci@vger.kernel.org
Subject: Re: [PATCH v3 04/11] dmaengine: switchtec-dma: fix channel leak on registration failure
Date: Mon, 27 Jul 2026 19:06:03 +0000	[thread overview]
Message-ID: <20260727190604.397DB1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260727181526.9672-5-logang@deltatee.com>

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

New issues:
- [High] Freeing DMA channels in error paths leaves dangling pointers in the `dma_dev->channels` list, leading to a Use-After-Free when accessed by the active channel status ISR.

Pre-existing issues:
- [High] The `switchtec_dma_remove()` function dereferences `swdma_dev` after it has been freed by the `device_release` callback.
- [High] Registering the channel status ISR before initializing the channel list head causes a NULL pointer dereference.
- [High] Pre-existing deadlock if a client callback attempts to abort or terminate the DMA channel.
- [High] Incorrect IRQ free API in `switchtec_dma_create()` error path guarantees an IRQ leak and subsequent Use-After-Free.
- [Medium] Missing `put_device()` in `switchtec_dma_create()` error path causes a reference count leak for the PCI device.
- [Medium] Missing `pci_free_irq_vectors()` on error paths in `switchtec_dma_create()` leaks MSI-X vectors.
--

--- Patch [4]: [PATCH v3 04/11] dmaengine: switchtec-dma: fix channel leak on registration failure ---
commit 58dd78b5d9196a368d9b2914fdfb2256ea81eef1
Author: Logan Gunthorpe <logang@deltatee.com>

dmaengine: switchtec-dma: fix channel leak on registration failure

switchtec_dma_chans_release() is called in three places but the
underlying memory is not freed in all of those places. In order to
clean this up, introduce a switchtec_dma_chans_free() helper that
will free the memory.

Link: https://lore.kernel.org/dmaengine/20260717223024.9BB8A1F000E9@smtp.kernel.org

> diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
> index 107769cca772f..13efd4189bbb4 100644
> --- a/drivers/dma/switchtec_dma.c
> +++ b/drivers/dma/switchtec_dma.c
> @@ -1176,6 +1176,16 @@ static int switchtec_dma_chans_release(struct pci_dev *pdev,
>  	return 0;
>  }
>  
> +static void switchtec_dma_chans_free(struct switchtec_dma_dev *swdma_dev)
> +{
> +	int i;
> +
> +	for (i = 0; i < swdma_dev->chan_cnt; i++)
> +		kfree(swdma_dev->swdma_chans[i]);

[Severity: High]
Does this code leak dangling pointers in the dma_dev->channels list?

The newly introduced switchtec_dma_chans_free() frees each swdma_chan but fails
to call list_del(&chan->device_node). If an interrupt occurs (e.g. spurious or
shared) before the ISR is disabled (or indefinitely if the ISR cleanup fails),
switchtec_dma_chan_status_isr() will iterate over this list and deference the
freed memory, leading to a Use-After-Free.

[ ... ]

> @@ -1317,6 +1321,7 @@ static int switchtec_dma_create(struct pci_dev *pdev)
>  
>  err_chans_release_exit:
>  	switchtec_dma_chans_release(pdev, swdma_dev);
> +	switchtec_dma_chans_free(swdma_dev);

[Severity: Medium]
This is a pre-existing issue, but does this error path leak the PCI device
reference count?

During probe, switchtec_dma_create() acquires the reference via
get_device(&pdev->dev). If dma_async_device_register() fails, the execution
jumps here. This path cleanly frees memory but fails to call put_device(dma->dev),
which leaks the reference count and prevents clean teardown on hot-unplug.

>  
>  err_exit:
>  	if (swdma_dev->chan_status_irq)

[Severity: High]
This is a pre-existing issue, but does this incorrect IRQ free API guarantee
an IRQ leak and subsequent Use-After-Free?

switchtec_dma_create() requests an MSI-X vector via pci_request_irq() using
the hardware vector index (e.g. 0). However, this error path calls free_irq()
instead of pci_free_irq().

This attempts to free the Linux IRQ number corresponding to the index (0),
which fails silently. Furthermore, because it's index 0, the
if (swdma_dev->chan_status_irq) condition prevents the free from even executing.
The ISR remains registered after swdma_dev is kfreed, leading to a UAF when
the IRQ fires.

[Severity: Medium]
This is a pre-existing issue, but does this error path also leak MSI-X vectors?

If pci_alloc_irq_vectors() succeeds, but subsequent steps like pci_request_irq()
or switchtec_dma_chans_enumerate() fail, the execution jumps to the err_exit
label. The error cleanup omits pci_free_irq_vectors(), leaking the allocated
vectors.

[ ... ]

For switchtec_dma_remove():

> static void switchtec_dma_remove(struct pci_dev *pdev)
> {
> 	struct switchtec_dma_dev *swdma_dev = pci_get_drvdata(pdev);
> 
> 	switchtec_dma_chans_release(pdev, swdma_dev);
> 
> 	rcu_assign_pointer(swdma_dev->pdev, NULL);
> 	synchronize_rcu();
> 
> 	pci_free_irq(pdev, swdma_dev->chan_status_irq, swdma_dev);
> 
> 	pci_free_irq_vectors(pdev);
> 
> 	dma_async_device_unregister(&swdma_dev->dma_dev);
> 
> 	iounmap(swdma_dev->bar);

[Severity: High]
This is a pre-existing issue, but does this dereference swdma_dev after it has
been freed?

During driver unbind, dma_async_device_unregister() drops the last reference
to the DMA device, which synchronously invokes switchtec_dma_release(). This
callback frees swdma_dev via kfree(swdma_dev). Immediately after, this
function attempts to access swdma_dev->bar in the iounmap() call, causing a
Use-After-Free.

For switchtec_dma_create():

> 	rc = pci_request_irq(pdev, irq, NULL, switchtec_dma_chan_status_isr,
> 			     swdma_dev, KBUILD_MODNAME);
> 	if (rc)
> 		goto err_exit;
> 
> 	swdma_dev->chan_status_irq = irq;
> 
> 	chan_cnt = readl(swdma_dev->bar + SWITCHTEC_REG_CHAN_CNT);
> 	if (!chan_cnt) {
> 		pci_err(pdev, "No channel configured.\n");
> 		rc = -ENXIO;
> 		goto err_exit;
> 	}
> 
> 	chan_cnt = switchtec_dma_chans_enumerate(swdma_dev, pdev, chan_cnt);

[Severity: High]
This is a pre-existing issue, but does registering the channel status ISR
before initializing the channel list head cause a NULL pointer dereference?

switchtec_dma_create() calls pci_request_irq() to register the ISR, then
proceeds to switchtec_dma_chans_enumerate() which calls
INIT_LIST_HEAD(&dma->channels).

Because dma_dev is allocated with kzalloc_obj, the channels.next pointer is
initially NULL. If an interrupt fires during this narrow window,
list_for_each_entry() in the ISR will compute a negative offset from NULL and
attempt to dereference it, leading to an immediate kernel panic.

For switchtec_dma_cleanup_completed():

> static void
> switchtec_dma_cleanup_completed(struct switchtec_dma_chan *swdma_chan)
> {
> [ ... ]
> 		do {
> 			dma_cookie_complete(&desc->txd);
> 			dma_descriptor_unmap(&desc->txd);
> 			dmaengine_desc_get_callback_invoke(&desc->txd, &res);

[Severity: High]
This is a pre-existing issue, but can this cause a deadlock if a client callback
attempts to abort or terminate the DMA channel?

switchtec_dma_cleanup_completed() acquires swdma_chan->complete_lock with
spin_lock_bh() and invokes the client callback synchronously here.

If the client calls dmaengine_terminate_all(), it invokes:

static int switchtec_dma_terminate_all(struct dma_chan *chan)
{
	struct switchtec_dma_chan *swdma_chan =
		container_of(chan, struct switchtec_dma_chan, dma_chan);

	spin_lock_bh(&swdma_chan->complete_lock);

This attempts to re-acquire the exact same complete_lock unconditionally, causing
a self-deadlock on a single CPU core.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260727181526.9672-1-logang@deltatee.com?part=4

  reply	other threads:[~2026-07-27 19:06 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-27 18:15 [PATCH v3 00/11] dmaengine: miscellaneous fixes for ioat, switchtec_dma and plx_dma Logan Gunthorpe
2026-07-27 18:15 ` [PATCH v3 01/11] dmaengine: switchtec-dma: fix double-free in switchtec_dma_free_desc() Logan Gunthorpe
2026-07-27 18:28   ` sashiko-bot
2026-07-27 20:42   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 02/11] dmaengine: switchtec-dma: fix resource leak in alloc_chan_resources Logan Gunthorpe
2026-07-27 18:40   ` sashiko-bot
2026-07-27 18:56     ` Logan Gunthorpe
2026-07-27 20:44   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 03/11] dmaengine: switchtec-dma: halt channel on alloc_chan_resources error Logan Gunthorpe
2026-07-27 18:51   ` sashiko-bot
2026-07-27 20:47     ` Frank Li
2026-07-27 21:28       ` Logan Gunthorpe
2026-07-27 18:15 ` [PATCH v3 04/11] dmaengine: switchtec-dma: fix channel leak on registration failure Logan Gunthorpe
2026-07-27 19:06   ` sashiko-bot [this message]
2026-07-27 20:52   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 05/11] dmaengine: switchtec-dma: make switchtec_dma_chans_release() void Logan Gunthorpe
2026-07-27 19:15   ` sashiko-bot
2026-07-27 20:54   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 06/11] dmaengine: switchtec-dma: fix chan_status_irq cleanup on create() error Logan Gunthorpe
2026-07-27 19:28   ` sashiko-bot
2026-07-27 20:55   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 07/11] dmaengine: switchtec-dma: disable channels before freeing on registration failure Logan Gunthorpe
2026-07-27 19:39   ` sashiko-bot
2026-07-27 21:21   ` Frank Li
2026-07-27 21:51     ` Logan Gunthorpe
2026-07-27 18:15 ` [PATCH v3 08/11] dmaengine: switchtec-dma: fix use-after-free of swdma_dev in remove() Logan Gunthorpe
2026-07-27 19:52   ` sashiko-bot
2026-07-27 21:23   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 09/11] dmaengine: ioat: disable relaxed ordering before registering the device Logan Gunthorpe
2026-07-27 20:06   ` sashiko-bot
2026-07-27 21:27   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 10/11] dmaengine: ioat: use sysfs_emit() in per-channel sysfs show() Logan Gunthorpe
2026-07-27 20:13   ` sashiko-bot
2026-07-27 21:28   ` Frank Li
2026-07-27 18:15 ` [PATCH v3 11/11] dmaengine: plx_dma: fix NULL pointer deref in plx_dma_isr() Logan Gunthorpe
2026-07-27 20:23   ` sashiko-bot
2026-07-27 21:29   ` Frank Li

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=20260727190604.397DB1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=dmaengine@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=logang@deltatee.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vkoul@kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.