From: sashiko-bot@kernel.org
To: Frank.Li@oss.nxp.com
Cc: vkoul@kernel.org, imx@lists.linux.dev, Frank.Li@kernel.org,
linux-pci@vger.kernel.org, dmaengine@vger.kernel.org
Subject: Re: [PATCH v7 2/9] dmaengine: Add safe API to combine configuration and preparation
Date: Thu, 21 May 2026 17:10:35 +0000 [thread overview]
Message-ID: <20260521171035.A82EA1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260521-dma_prep_config-v7-2-1f73f4899883@nxp.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Calling `device_config` or `device_prep_slave_sg` while holding a spinlock with interrupts disabled (`spin_lock_irqsave`) will cause lockups and `WARN_ON_ONCE` in drivers that use bottom-half locks.
- [Medium] `spinlock_flags` may be used uninitialized and the lock may become unbalanced due to re-evaluation of `chan->device->device_prep_config_sg` across an opaque function call.
Pre-existing issues:
- [Critical] The function `dmaengine_prep_config_single_safe` passes a stack-allocated `scatterlist` to the DMA engine driver, which causes a stack use-after-free if the driver defers processing the scatterlist.
--
commit d2363736f5c7b002b0f30c81cef1791d2f12abd2
Author: Frank Li <Frank.Li@nxp.com>
Subject: dmaengine: Add safe API to combine configuration and preparation
Introduce new safe APIs to atomically combine slave configuration and transfer
preparation. The new functions fall back to calling slave_config and
prep_slave_sg under a channel spinlock if the device doesn't support the
atomic callback.
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index defa377d2ef54..6fe46c0c94527 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
[ ... ]
> +static inline struct dma_async_tx_descriptor *
> +dmaengine_prep_config_sg_safe(struct dma_chan *chan, struct scatterlist *sgl,
> + unsigned int sg_len,
> + enum dma_transfer_direction dir,
> + unsigned long flags,
> + struct dma_slave_config *config)
> +{
> + struct dma_async_tx_descriptor *tx;
> + unsigned long spinlock_flags;
> +
> + if (!chan || !chan->device)
> + return NULL;
> +
> + if (!chan->device->device_prep_config_sg)
> + spin_lock_irqsave(&chan->lock, spinlock_flags);
> +
> + tx = dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, config);
[Severity: High]
Will this cause lockups or warnings in drivers that use bottom-half locks?
Since spin_lock_irqsave() disables hard interrupts, calling into
dmaengine_prep_config_sg() invokes the underlying DMA driver's
device_prep_slave_sg() or device_config() callbacks. Some drivers use
bottom-half locks in these implementations:
dmaengine_prep_config_sg_safe()
spin_lock_irqsave()
dmaengine_prep_config_sg()
chan->device->device_prep_slave_sg()
td_prep_slave_sg()
td_desc_get()
spin_lock_bh()
When the driver eventually calls spin_unlock_bh(), it invokes
local_bh_enable(), which triggers a WARN_ON_ONCE(irqs_disabled()) because
hard interrupts were disabled by the outer spin_lock_irqsave().
> +
> + if (!chan->device->device_prep_config_sg)
> + spin_unlock_irqrestore(&chan->lock, spinlock_flags);
[Severity: Medium]
Could this lead to an uninitialized variable usage or an unbalanced lock?
The condition checking chan->device->device_prep_config_sg is evaluated
twice, before and after calling dmaengine_prep_config_sg(). Because that
function invokes opaque function pointers passing chan, the compiler must
assume memory reachable through chan might be modified.
This forces the compiler to consider a control flow path where the condition
is initially false (skipping spin_lock_irqsave and leaving spinlock_flags
uninitialized) but evaluates to true after the opaque call, leading to
spin_unlock_irqrestore() with uninitialized flags and an unbalanced lock.
Even if this doesn't happen dynamically, it can emit a -Wmaybe-uninitialized
warning that breaks builds with -Werror. Caching the condition in a local
boolean variable would prevent this.
> +
> + return tx;
> +}
> +
> +/**
> + * dmaengine_prep_config_single_safe - prepare a single-buffer DMA transfer
> + * with atomic slave configuration update
[ ... ]
> +static inline struct dma_async_tx_descriptor *
> +dmaengine_prep_config_single_safe(struct dma_chan *chan, dma_addr_t buf,
> + size_t len, enum dma_transfer_direction dir,
> + unsigned long flags,
> + struct dma_slave_config *config)
> +{
> + struct scatterlist sg;
> +
> + sg_init_table(&sg, 1);
> + sg_dma_address(&sg) = buf;
> + sg_dma_len(&sg) = len;
> +
> + return dmaengine_prep_config_sg_safe(chan, &sg, 1, dir, flags, config);
[Severity: Critical]
This is a pre-existing issue, but does passing a stack-allocated scatterlist
to the driver cause a stack use-after-free if the driver defers processing?
The scatterlist sg is allocated on the stack and passed down to the
underlying DMA engine's device_prep_slave_sg() callback. While some drivers
consume the scatterlist synchronously, others save the pointer to process
it asynchronously later:
uniphier_mdmac_prep_slave_sg()
md->sgl = sgl;
uniphier_mdmac_handle()
dereferences md->sgl
Because dmaengine_prep_config_single_safe() returns immediately, the stack
frame is destroyed. When the DMA driver later accesses the saved pointer
from an IRQ context, it accesses freed stack memory.
This pattern already exists in dmaengine_prep_slave_single(), but
replicating it here propagates the regression to the new API.
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260521-dma_prep_config-v7-0-1f73f4899883@nxp.com?part=2
next prev parent reply other threads:[~2026-05-21 17:10 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-21 15:32 [PATCH v7 0/9] dmaengine: Add new API to combine configuration and descriptor preparation Frank.Li
2026-05-21 15:32 ` [PATCH v7 1/9] dmaengine: Add API to combine configuration and preparation (sg and single) Frank.Li
2026-05-21 15:32 ` [PATCH v7 2/9] dmaengine: Add safe API to combine configuration and preparation Frank.Li
2026-05-21 17:10 ` sashiko-bot [this message]
2026-05-21 15:32 ` [PATCH v7 3/9] PCI: endpoint: pci-epf-test: Use dmaenigne_prep_config_single() to simplify code Frank.Li
2026-05-21 17:31 ` sashiko-bot
2026-07-09 19:52 ` Bjorn Helgaas
2026-05-21 15:32 ` [PATCH v7 4/9] dmaengine: dw-edma: Use new .device_prep_config_sg() callback Frank.Li
2026-05-21 17:56 ` sashiko-bot
2026-05-21 15:32 ` [PATCH v7 5/9] dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer() Frank.Li
2026-05-21 18:10 ` sashiko-bot
2026-05-21 15:32 ` [PATCH v7 6/9] nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer Frank.Li
2026-05-21 18:31 ` sashiko-bot
2026-05-21 15:32 ` [PATCH v7 7/9] nvmet: pci-epf: Use dmaengine_prep_config_single_safe() API Frank.Li
2026-05-21 19:05 ` sashiko-bot
2026-05-21 15:32 ` [PATCH v7 8/9] PCI: epf-mhi: Use dmaengine_prep_config_single() to simplify code Frank.Li
2026-05-21 15:32 ` [PATCH v7 9/9] crypto: atmel: Use dmaengine_prep_config_sg() API Frank.Li
2026-07-02 15:26 ` [PATCH v7 0/9] dmaengine: Add new API to combine configuration and descriptor preparation Vinod Koul
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=20260521171035.A82EA1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Frank.Li@kernel.org \
--cc=Frank.Li@oss.nxp.com \
--cc=dmaengine@vger.kernel.org \
--cc=imx@lists.linux.dev \
--cc=linux-pci@vger.kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox