DMA Engine development
 help / color / mirror / Atom feed
* [PATCH] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg
@ 2026-09-09  3:38 Baineng Shou
  2026-09-09  3:50 ` sashiko-bot
  2026-09-09 21:01 ` Frank Li
  0 siblings, 2 replies; 6+ messages in thread
From: Baineng Shou @ 2026-09-09  3:38 UTC (permalink / raw)
  To: vkoul; +Cc: Frank.Li, dmaengine, linux-kernel, Baineng Shou

In mmp_pdma_prep_slave_sg(), for_each_sg() iterates the scatterlist
putting each entry into 'sg', but the entry length is read from 'sgl'
(the list head) instead of 'sg' (the current entry):

    for_each_sg(sgl, sg, sg_len, i) {
        addr = sg_dma_address(sg);
        avail = sg_dma_len(sgl);   /* should be 'sg' */

Consequently 'avail' is always the length of the first entry. For
multi-sg lists this causes out-of-bounds reads when a later entry is
shorter than the first, and silent data loss when it is longer.
Single-sg or uniformly-sized lists happen to mask the issue.

Fixes: c8acd6aa6bed3 ("dmaengine: mmp-pdma support")
Signed-off-by: Baineng Shou <shoubaineng@gmail.com>
---
 drivers/dma/mmp_pdma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index 386e85cd4882..e90fd2023af7 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -713,7 +713,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
 
 	for_each_sg(sgl, sg, sg_len, i) {
 		addr = sg_dma_address(sg);
-		avail = sg_dma_len(sgl);
+		avail = sg_dma_len(sg);
 
 		do {
 			len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg
  2026-09-09  3:38 [PATCH] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg Baineng Shou
@ 2026-09-09  3:50 ` sashiko-bot
  2026-09-09 21:01 ` Frank Li
  1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-09-09  3:50 UTC (permalink / raw)
  To: Baineng Shou; +Cc: vkoul, dmaengine, Frank.Li

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

Pre-existing issues:
- [High] Use-After-Free during descriptor list cleanup on error paths.
- [High] Tasklets are not killed during device removal, leading to a potential Use-After-Free.
- [High] Stale state and missing initialization for `chan->dir` and `chan->dcmd` breaking memory-to-memory DMA.
- [High] Unprotected overwrite of channel-wide `byte_align` flag by subsequent prep calls.
--

commit 67c707d8b7f67369582be4fc75b9289a8abcab3a
Author: Baineng Shou <shoubaineng@gmail.com>

dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg

In mmp_pdma_prep_slave_sg(), for_each_sg() iterates the scatterlist
putting each entry into 'sg', but the entry length is read from 'sgl'
(the list head) instead of 'sg' (the current entry):
[ ... ]
Single-sg or uniformly-sized lists happen to mask the issue.

> diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
> index 386e85cd4882a..e90fd2023af71 100644
> --- a/drivers/dma/mmp_pdma.c
> +++ b/drivers/dma/mmp_pdma.c
> @@ -713,7 +713,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
>  
>  	for_each_sg(sgl, sg, sg_len, i) {
>  		addr = sg_dma_address(sg);
> -		avail = sg_dma_len(sgl);
> +		avail = sg_dma_len(sg);
>  
>  		do {
>  			len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);

[Severity: High]
This isn't a regression introduced by this patch, but this lockless
modification of chan->byte_align appears to silently overwrite the hardware
alignment requirement for any earlier descriptors that are still pending or
running:

drivers/dma/mmp_pdma.c:mmp_pdma_prep_slave_sg() {
    ...
		do {
			len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);
			if (addr & 0x7)
				chan->byte_align = true;
    ...
}

If a client prepares multiple scatterlists on the same channel before
submitting them, does the last prepared scatterlist overwrite
chan->byte_align for the entire channel?

When earlier transactions are eventually started via enable_chan(), they
are submitted to hardware with the overwritten alignment configuration:

drivers/dma/mmp_pdma.c:enable_chan() {
    ...
	if (phy->vchan->byte_align)
		dalgn |= 1 << phy->idx;
    ...
}

Could this lead to hardware misbehavior or data corruption due to incorrect
alignment configuration?


[Severity: High]
This is a pre-existing regression, but I have a question about the error
handling path further down in mmp_pdma_prep_slave_sg():

drivers/dma/mmp_pdma.c:mmp_pdma_prep_slave_sg() {
    ...
fail:
	if (first)
		mmp_pdma_free_desc_list(chan, &first->tx_list);
	return NULL;
}

The cleanup sequence explicitly passes &first->tx_list, which is embedded
in the descriptor to be freed.

drivers/dma/mmp_pdma.c:mmp_pdma_free_desc_list() {
    ...
	list_for_each_entry_safe(desc, _desc, list, node) {
		list_del(&desc->node);
		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
	}
    ...
}

The list iteration macro safely caches the next element, but it reads from
and writes to the list head during the update and list_del() steps.

If the list head (&first->tx_list) is embedded in a freed element (because
the 'first' descriptor is freed during the first iteration), wouldn't this
result in a use-after-free when subsequent list manipulations or the loop's
next-entry calculation dereference the freed memory?


[Severity: High]
This is a pre-existing regression, but there might be an initialization
problem in mmp_pdma_prep_memcpy() when reusing channels:

drivers/dma/mmp_pdma.c:mmp_pdma_prep_memcpy() {
    ...
	if (!chan->dir) {
		chan->dir = DMA_MEM_TO_MEM;
		chan->dcmd = DCMD_INCTRGADDR | DCMD_INCSRCADDR;
		chan->dcmd |= DCMD_BURST32;
	}
    ...
}

Does the !chan->dir condition fail to clear stale state from a previous slave
DMA session?

When a channel allocated from the shared pool is used for slave DMA (e.g.,
DMA_MEM_TO_DEV), it modifies chan->dir and chan->dcmd. When the channel is
freed via mmp_pdma_free_chan_resources(), these fields are not cleared.

If the channel is later requested for dma_memcpy, mmp_pdma_prep_memcpy() will
use the stale state. Could this incorrectly omit DCMD_INCTRGADDR (leaving the
target address static) and apply the wrong address increment logic, resulting
in corrupted memory writes?


[Severity: High]
This is a pre-existing regression, but I noticed a potential teardown
problem in the device removal path:

drivers/dma/mmp_pdma.c:mmp_pdma_remove() {
    ...
	dma_async_device_unregister(&pdev->device);
}

The device removal teardown is missing necessary tasklet_kill() calls for
all initialized channels before their memory backing is freed by devres.

Since chan is managed by devm_kzalloc(), it is automatically freed after
mmp_pdma_remove() completes.

If a tasklet was scheduled right before free_irq() but hasn't executed,
will it run after removal completes and access the freed chan structure,
causing a use-after-free?

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg
  2026-09-09  3:38 [PATCH] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg Baineng Shou
  2026-09-09  3:50 ` sashiko-bot
@ 2026-09-09 21:01 ` Frank Li
  2026-09-10  2:16   ` [PATCH v2] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg() Baineng Shou
  1 sibling, 1 reply; 6+ messages in thread
From: Frank Li @ 2026-09-09 21:01 UTC (permalink / raw)
  To: Baineng Shou; +Cc: vkoul, Frank.Li, dmaengine, linux-kernel

On Wed, Sep 09, 2026 at 11:38:41AM +0800, Baineng Shou wrote:

Need () for funciton mmp_pdma_prep_slave_sg()

Frank

>
> In mmp_pdma_prep_slave_sg(), for_each_sg() iterates the scatterlist
> putting each entry into 'sg', but the entry length is read from 'sgl'
> (the list head) instead of 'sg' (the current entry):
>
>     for_each_sg(sgl, sg, sg_len, i) {
>         addr = sg_dma_address(sg);
>         avail = sg_dma_len(sgl);   /* should be 'sg' */
>
> Consequently 'avail' is always the length of the first entry. For
> multi-sg lists this causes out-of-bounds reads when a later entry is
> shorter than the first, and silent data loss when it is longer.
> Single-sg or uniformly-sized lists happen to mask the issue.
>
> Fixes: c8acd6aa6bed3 ("dmaengine: mmp-pdma support")
> Signed-off-by: Baineng Shou <shoubaineng@gmail.com>
> ---
>  drivers/dma/mmp_pdma.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
> index 386e85cd4882..e90fd2023af7 100644
> --- a/drivers/dma/mmp_pdma.c
> +++ b/drivers/dma/mmp_pdma.c
> @@ -713,7 +713,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
>
>         for_each_sg(sgl, sg, sg_len, i) {
>                 addr = sg_dma_address(sg);
> -               avail = sg_dma_len(sgl);
> +               avail = sg_dma_len(sg);
>
>                 do {
>                         len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg()
  2026-09-09 21:01 ` Frank Li
@ 2026-09-10  2:16   ` Baineng Shou
  2026-09-10  2:27     ` sashiko-bot
  2026-09-10 16:38     ` Frank Li
  0 siblings, 2 replies; 6+ messages in thread
From: Baineng Shou @ 2026-09-10  2:16 UTC (permalink / raw)
  To: vkoul; +Cc: Frank.Li, dmaengine, linux-kernel, Baineng Shou

In mmp_pdma_prep_slave_sg(), for_each_sg() iterates the scatterlist
putting each entry into 'sg', but the entry length is read from 'sgl'
(the list head) instead of 'sg' (the current entry):

    for_each_sg(sgl, sg, sg_len, i) {
        addr = sg_dma_address(sg);
        avail = sg_dma_len(sgl);   /* should be 'sg' */

Consequently 'avail' is always the length of the first entry. For
multi-sg lists this causes out-of-bounds reads when a later entry is
shorter than the first, and silent data loss when it is longer.
Single-sg or uniformly-sized lists happen to mask the issue.

Fixes: c8acd6aa6bed3 ("dmaengine: mmp-pdma support")
Signed-off-by: Baineng Shou <shoubaineng@gmail.com>
---

Changes in v2:
- Add () to the function name in the subject, per Frank Li's review.

 drivers/dma/mmp_pdma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index 386e85cd4882..e90fd2023af7 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -713,7 +713,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
 
 	for_each_sg(sgl, sg, sg_len, i) {
 		addr = sg_dma_address(sg);
-		avail = sg_dma_len(sgl);
+		avail = sg_dma_len(sg);
 
 		do {
 			len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg()
  2026-09-10  2:16   ` [PATCH v2] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg() Baineng Shou
@ 2026-09-10  2:27     ` sashiko-bot
  2026-09-10 16:38     ` Frank Li
  1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-09-10  2:27 UTC (permalink / raw)
  To: Baineng Shou; +Cc: vkoul, Frank.Li, dmaengine

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

Pre-existing issues:
- [High] Use-after-free of list head in error path when freeing descriptor chain because the list head is embedded in the first element being freed.
--

commit 5f1b06ea0ed695c8b6d14358fdfb48649d799152
Author: Baineng Shou <shoubaineng@gmail.com>

dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg()

This commit fixes a bug in mmp_pdma_prep_slave_sg() where for_each_sg()
read the entry length from the list head instead of the current entry.
This led to out-of-bounds reads or silent data loss when handling
multi-sg lists of varying entry lengths.

> diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
> index 386e85cd4882a..e90fd2023af71 100644
> --- a/drivers/dma/mmp_pdma.c
> +++ b/drivers/dma/mmp_pdma.c
> @@ -713,7 +713,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
>  
>  	for_each_sg(sgl, sg, sg_len, i) {
>  		addr = sg_dma_address(sg);
> -		avail = sg_dma_len(sgl);
> +		avail = sg_dma_len(sg);
>  
>  		do {
>  			len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);

[Severity: High]
This is a pre-existing issue, but I noticed a potential use-after-free
if a subsequent descriptor allocation fails further down in this function.

If a subsequent allocation fails, the error path is taken:

drivers/dma/mmp_pdma.c:mmp_pdma_prep_slave_sg() {
    ...
fail:
	if (first)
		mmp_pdma_free_desc_list(chan, &first->tx_list);
	return NULL;
}

Inside mmp_pdma_free_desc_list(), list_for_each_entry_safe() iterates
over the list and frees each descriptor:

drivers/dma/mmp_pdma.c:mmp_pdma_free_desc_list() {
    ...
	list_for_each_entry_safe(desc, _desc, list, node) {
		list_del(&desc->node);
		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
	}
}

Because the list head (&first->tx_list) is embedded within the first
descriptor, it is freed during the first iteration.

If there are multiple elements in the list, the second iteration calls
list_del(&desc->node), which modifies pointers that point back to the
now-freed list head. 

Does this result in a use-after-free write into the freed descriptor?

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg()
  2026-09-10  2:16   ` [PATCH v2] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg() Baineng Shou
  2026-09-10  2:27     ` sashiko-bot
@ 2026-09-10 16:38     ` Frank Li
  1 sibling, 0 replies; 6+ messages in thread
From: Frank Li @ 2026-09-10 16:38 UTC (permalink / raw)
  To: Baineng Shou; +Cc: vkoul, Frank.Li, dmaengine, linux-kernel

On Thu, Sep 10, 2026 at 10:16:52AM +0800, Baineng Shou wrote:
> [You don't often get email from shoubaineng@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> In mmp_pdma_prep_slave_sg(), for_each_sg() iterates the scatterlist
> putting each entry into 'sg', but the entry length is read from 'sgl'
> (the list head) instead of 'sg' (the current entry):
>
>     for_each_sg(sgl, sg, sg_len, i) {
>         addr = sg_dma_address(sg);
>         avail = sg_dma_len(sgl);   /* should be 'sg' */
>
> Consequently 'avail' is always the length of the first entry. For
> multi-sg lists this causes out-of-bounds reads when a later entry is
> shorter than the first, and silent data loss when it is longer.
> Single-sg or uniformly-sized lists happen to mask the issue.
>
> Fixes: c8acd6aa6bed3 ("dmaengine: mmp-pdma support")
> Signed-off-by: Baineng Shou <shoubaineng@gmail.com>
> ---

Don't post new v2 patch to old email v1 thread.

Reviewed-by: Frank Li <Frank.Li@nxp.com>


>
> Changes in v2:
> - Add () to the function name in the subject, per Frank Li's review.
>
>  drivers/dma/mmp_pdma.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
> index 386e85cd4882..e90fd2023af7 100644
> --- a/drivers/dma/mmp_pdma.c
> +++ b/drivers/dma/mmp_pdma.c
> @@ -713,7 +713,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
>
>         for_each_sg(sgl, sg, sg_len, i) {
>                 addr = sg_dma_address(sg);
> -               avail = sg_dma_len(sgl);
> +               avail = sg_dma_len(sg);
>
>                 do {
>                         len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-10 16:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09  3:38 [PATCH] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg Baineng Shou
2026-09-09  3:50 ` sashiko-bot
2026-09-09 21:01 ` Frank Li
2026-09-10  2:16   ` [PATCH v2] dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg() Baineng Shou
2026-09-10  2:27     ` sashiko-bot
2026-09-10 16:38     ` Frank Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox