DMA Engine development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Rosen Penev" <rosenp@gmail.com>
Cc: Frank.Li@kernel.org, vkoul@kernel.org, dmaengine@vger.kernel.org
Subject: Re: [PATCHv2 3/9] dmaengine: mv_xor: bound maximum channels for Armada 37xx
Date: Thu, 11 Jun 2026 21:22:20 +0000	[thread overview]
Message-ID: <20260611212221.35FCC1F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260611210721.81979-4-rosenp@gmail.com>

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

Pre-existing issues:
- [High] The return value of `clk_prepare_enable()` is ignored, leading to potential warnings and hardware hangs if the clock fails to enable.
- [High] The driver fails to kill the scheduled `irq_tasklet` on error and teardown paths, leading to a Use-After-Free.
- [High] In `mv_xor_channel_remove()`, DMA memory is freed before the interrupt handler is disabled, creating a race condition leading to Use-After-Free.
- [High] The driver lacks a `.remove` callback and does not set `.suppress_bind_attrs = true`, causing severe resource leaks and use-after-free on sysfs unbind.
- [High] The IRQ handler is requested and unmasked before the channel's spinlock and lists are initialized, resulting in a race condition causing a NULL pointer dereference.
- [High] The inline dummy buffers (`dummy_src`, `dummy_dst`) share cachelines with struct members and their DMA mapping directions are reversed.
--

commit f06921d6568212d3de528ed83169a5d04733b815
Author: Rosen Penev <rosenp@gmail.com>

dmaengine: mv_xor: bound maximum channels for Armada 37xx

This commit adds a missing bounds check for the max_channels calculation
on Armada 37xx. It ensures max_channels does not exceed MV_XOR_MAX_CHANNELS
based on num_present_cpus(), preventing the probe loop from writing past
the end of the xordev->channels[] array.

> diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
> index 25ed61f1b0899..68f0880ad441f 100644
> --- a/drivers/dma/mv_xor.c
> +++ b/drivers/dma/mv_xor.c
[ ... ]
> @@ -1376,7 +1376,8 @@ static int mv_xor_probe(struct platform_device *pdev)
>  	 */
>  	max_engines = num_present_cpus();
>  	if (xordev->xor_type == XOR_ARMADA_37XX)
> -		max_channels =	num_present_cpus();
> +		max_channels = min_t(unsigned int, MV_XOR_MAX_CHANNELS,
> +				     num_present_cpus());
>  	else
>  		max_channels = min_t(unsigned int,
>  				     MV_XOR_MAX_CHANNELS,

While reviewing this patch, I noticed a few pre-existing issues in the
surrounding code that might need attention.

[Severity: High]
This isn't a bug introduced by this patch, but looking at mv_xor_probe()
the return value of clk_prepare_enable() appears to be ignored:

    if (!IS_ERR(xordev->clk))
        clk_prepare_enable(xordev->clk);

If the clock fails to enable, would the driver continue probing and
subsequently hang the hardware bus during I/O accesses?

Additionally, the error path unconditionally executes clk_disable_unprepare():

    if (!IS_ERR(xordev->clk)) {
        clk_disable_unprepare(xordev->clk);
        clk_put(xordev->clk);
    }

Could this trigger a state imbalance warning in the clock core if the clock
was never successfully enabled?

[Severity: High]
This is a pre-existing issue, but does mv_xor_channel_remove() miss killing
the irq_tasklet before freeing the channel?

drivers/dma/mv_xor.c:mv_xor_channel_remove() {
    ...
    free_irq(mv_chan->irq, mv_chan);

    return 0;
}

Could a pending tasklet run after mv_chan is freed by devres, leading to
a use-after-free? It looks like the err_free_irq path in mv_xor_channel_add()
has a similar pattern and might also need a tasklet_kill() before returning.

[Severity: High]
This is a pre-existing issue, but is there a race condition in
mv_xor_channel_remove() when freeing DMA memory?

drivers/dma/mv_xor.c:mv_xor_channel_remove() {
    ...
    dma_free_wc(dev, MV_XOR_POOL_SIZE,
                mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool);
    dma_unmap_single(dev, mv_chan->dummy_src_addr,
                     MV_XOR_MIN_BYTE_COUNT, DMA_FROM_DEVICE);
    dma_unmap_single(dev, mv_chan->dummy_dst_addr,
                     MV_XOR_MIN_BYTE_COUNT, DMA_TO_DEVICE);
    ...
    free_irq(mv_chan->irq, mv_chan);
}

Since dma_free_wc() and dma_unmap_single() are called before free_irq(), could
an interrupt fire during this window and schedule the tasklet to access the
freed descriptor buffers?

[Severity: High]
This isn't a bug introduced by this patch, but does the driver lack a
.remove callback and omit .suppress_bind_attrs = true?

drivers/dma/mv_xor.c:
static struct platform_driver mv_xor_driver = {
    .probe          = mv_xor_probe,
    .suspend        = mv_xor_suspend,
    .resume         = mv_xor_resume,
    .driver         = {
        .name           = MV_XOR_NAME,
        .of_match_table = mv_xor_dt_ids,
    },
};

If the root user manually unbinds the device via sysfs, would this leak DMA
device registrations and hardware interrupts? Could a subsequent interrupt
access the devm-freed mv_chan and cause a use-after-free?

[Severity: High]
This is a pre-existing issue, but does requesting and unmasking the
interrupt before initializing the channel's lock and lists risk a NULL
pointer dereference?

drivers/dma/mv_xor.c:mv_xor_channel_add() {
    ...
    ret = request_irq(mv_chan->irq, mv_xor_interrupt_handler,
                      0, dev_name(&pdev->dev), mv_chan);
    if (ret)
        goto err_free_dma;

    mv_chan_unmask_interrupts(mv_chan);

    ...

    spin_lock_init(&mv_chan->lock);
    INIT_LIST_HEAD(&mv_chan->chain);
    INIT_LIST_HEAD(&mv_chan->completed_slots);
}

If an interrupt fires immediately after being unmasked, wouldn't the tasklet
attempt to acquire an uninitialized spinlock and iterate over the
uninitialized mv_chan->chain list?

[Severity: High]
This isn't a bug introduced by this patch, but do the inline dummy buffers
share cachelines with adjacent struct members?

drivers/dma/mv_xor.h:struct mv_xor_chan {
    ...
    int                     op_in_desc;
    char                    dummy_src[MV_XOR_MIN_BYTE_COUNT];
    char                    dummy_dst[MV_XOR_MIN_BYTE_COUNT];
    dma_addr_t              dummy_src_addr, dummy_dst_addr;
}

In mv_xor_channel_add(), the mapping directions appear to be reversed:

    mv_chan->dummy_src_addr = dma_map_single(dma_dev->dev,
        mv_chan->dummy_src, MV_XOR_MIN_BYTE_COUNT, DMA_FROM_DEVICE);
    ...
    mv_chan->dummy_dst_addr = dma_map_single(dma_dev->dev,
        mv_chan->dummy_dst, MV_XOR_MIN_BYTE_COUNT, DMA_TO_DEVICE);

Could mapping dummy_src as DMA_FROM_DEVICE cause the DMA API to perform
a cache invalidation that clobbers dirty, unflushed CPU writes to adjacent
members like op_in_desc?

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

  reply	other threads:[~2026-06-11 21:22 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-11 21:07 [PATCHv2 0/9] dma: mv_xor: convert to devm resource management Rosen Penev
2026-06-11 21:07 ` [PATCHv2 1/9] dmaengine: mv_xor: initialize chan state before requesting IRQ Rosen Penev
2026-06-11 21:20   ` sashiko-bot
2026-06-11 21:07 ` [PATCHv2 2/9] dmaengine: mv_xor: fix use-after-free in probe error path Rosen Penev
2026-06-11 21:24   ` sashiko-bot
2026-06-11 21:07 ` [PATCHv2 3/9] dmaengine: mv_xor: bound maximum channels for Armada 37xx Rosen Penev
2026-06-11 21:22   ` sashiko-bot [this message]
2026-06-11 21:07 ` [PATCHv2 4/9] dmaengine: mv_xor: abort channel before freeing resources on timeout Rosen Penev
2026-06-11 21:07 ` [PATCHv2 5/9] dmaengine: mv_xor: use devm_clk_get_optional_enabled Rosen Penev
2026-06-11 21:19   ` sashiko-bot
2026-06-11 21:07 ` [PATCHv2 6/9] dmaengine: mv_xor: switch to of_irq_get() Rosen Penev
2026-06-11 21:07 ` [PATCHv2 7/9] dmaengine: mv_xor: use devm for dma pool and irq Rosen Penev
2026-06-11 21:22   ` sashiko-bot
2026-06-11 21:07 ` [PATCHv2 8/9] dmaengine: mv_xor: allocate dummy buffers with dmam_alloc_coherent Rosen Penev
2026-06-11 21:07 ` [PATCHv2 9/9] dmaengine: mv_xor: add missing platform remove function Rosen Penev
2026-06-11 21:19   ` sashiko-bot

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=20260611212221.35FCC1F00A3A@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=dmaengine@vger.kernel.org \
    --cc=rosenp@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox