DMA Engine development
 help / color / mirror / Atom feed
* [PATCH] dmaengine: xilinx: Fix wild pointer dereference on empty segment list
@ 2026-10-23  6:58 Li Ximo
  2026-10-23  7:10 ` sashiko-bot
  0 siblings, 1 reply; 3+ messages in thread
From: Li Ximo @ 2026-10-23  6:58 UTC (permalink / raw)
  To: Vinod Koul, Michal Simek
  Cc: Frank Li, dmaengine, linux-arm-kernel, linux-kernel, Wang Haoran,
	Li Ximo

From: Wang Haoran <haoranwangsec@gmail.com>

list_first_entry() does not return NULL when the list is empty; it
returns the result of container_of() on the list head, i.e. a wild
pointer that points into the enclosing xilinx_dma_tx_descriptor rather
than to a valid segment. Dereferencing it reads or writes unrelated
descriptor memory. This was found by code audit.

In xilinx_dma_prep_peripheral_dma_vec(), xilinx_dma_prep_slave_sg()
and xilinx_mcdma_prep_slave_sg(), the loop that populates
desc->segments never executes when the transfer length is zero
(nb == 0, sg_len == 0, or all vecs[i].len / sg_dma_len() entries are
zero). The dmaengine inline wrappers do not reject such zero-length
transfers, so they reach the driver unchanged. The unconditional
list_first_entry() then yields a wild pointer: the following
head->phys / segment->phys reads are out-of-bounds reads within the
descriptor slab, and on the DMA_MEM_TO_DEV path the hw.control
read-modify-write corrupts the descriptor. In
xilinx_dma_prep_peripheral_dma_vec() the empty case additionally
dereferences the never-initialized 'segment' pointer. Similarly, in
xilinx_dma_get_metadata_ptr(), a descriptor with an empty segment
list produces a wild 'seg' whose hw.app pointer is handed back to the
DMA client.

Guard each list_first_entry() call: in the three prep functions, bail
out through the existing error path (freeing the descriptor and
returning NULL, consistent with the current failure handling) when
desc->segments is still empty after the build loop; in
xilinx_dma_get_metadata_ptr(), use list_first_entry_or_null() and
return NULL when there is no segment.

Reported-by: Wang Haoran <haoranwangsec@gmail.com>
Reported-by: Li Ximo <lixicaicai@gmail.com>
Signed-off-by: Wang Haoran <haoranwangsec@gmail.com>
---
 drivers/dma/xilinx/xilinx_dma.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index cffe7c6fa..07f52f841 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -650,8 +650,11 @@ static void *xilinx_dma_get_metadata_ptr(struct dma_async_tx_descriptor *tx,
 	struct xilinx_axidma_tx_segment *seg;
 
 	*max_len = *payload_len = sizeof(u32) * XILINX_DMA_NUM_APP_WORDS;
-	seg = list_first_entry(&desc->segments,
-			       struct xilinx_axidma_tx_segment, node);
+	seg = list_first_entry_or_null(&desc->segments,
+				       struct xilinx_axidma_tx_segment, node);
+	if (!seg)
+		return NULL;
+
 	return seg->hw.app;
 }
 
@@ -2305,6 +2308,9 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_peripheral_dma_vec(
 		}
 	}
 
+	if (list_empty(&desc->segments))
+		goto error;
+
 	head = list_first_entry(&desc->segments, struct xilinx_axidma_tx_segment, node);
 	desc->async_tx.phys = head->phys;
 
@@ -2406,6 +2412,9 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg(
 		}
 	}
 
+	if (list_empty(&desc->segments))
+		goto error;
+
 	segment = list_first_entry(&desc->segments,
 				   struct xilinx_axidma_tx_segment, node);
 	desc->async_tx.phys = segment->phys;
@@ -2613,6 +2622,9 @@ xilinx_mcdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
 		}
 	}
 
+	if (list_empty(&desc->segments))
+		goto error;
+
 	segment = list_first_entry(&desc->segments,
 				   struct xilinx_aximcdma_tx_segment, node);
 	desc->async_tx.phys = segment->phys;
-- 
2.30.2


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

* Re: [PATCH] dmaengine: xilinx: Fix wild pointer dereference on empty segment list
  2026-10-23  6:58 [PATCH] dmaengine: xilinx: Fix wild pointer dereference on empty segment list Li Ximo
@ 2026-10-23  7:10 ` sashiko-bot
  2026-10-27 19:34   ` Frank Li
  0 siblings, 1 reply; 3+ messages in thread
From: sashiko-bot @ 2026-10-23  7:10 UTC (permalink / raw)
  To: Li Ximo; +Cc: dmaengine, vkoul, Frank.Li

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] dmaengine: xilinx: NULL return in xilinx_dma_get_metadata_ptr()
--

commit 5ff31a1fefdaf467f495be421ba38281e2cbd1a6
Author: Wang Haoran <haoranwangsec@gmail.com>

dmaengine: xilinx: Fix wild pointer dereference on empty segment list

This commit guards against empty segment lists in the Xilinx DMA prep
functions and in xilinx_dma_get_metadata_ptr() to avoid dereferencing wild
pointers from list_first_entry().

> diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> index cffe7c6fa6405..07f52f8412b10 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -650,8 +650,11 @@ static void *xilinx_dma_get_metadata_ptr(struct dma_async_tx_descriptor *tx,
>  	struct xilinx_axidma_tx_segment *seg;
>  
>  	*max_len = *payload_len = sizeof(u32) * XILINX_DMA_NUM_APP_WORDS;
> -	seg = list_first_entry(&desc->segments,
> -			       struct xilinx_axidma_tx_segment, node);
> +	seg = list_first_entry_or_null(&desc->segments,
> +				       struct xilinx_axidma_tx_segment, node);
> +	if (!seg)
> +		return NULL;

[Severity: High]
Should xilinx_dma_get_metadata_ptr() return an ERR_PTR() (such as
ERR_PTR(-EINVAL) or ERR_PTR(-ENODATA)) before modifying *max_len and
*payload_len when desc->segments is empty, rather than returning NULL?

The caller in drivers/dma/dmaengine.c uses the ERR_PTR() error convention and
directly returns the result of metadata_ops->get_ptr():

void *dmaengine_desc_get_metadata_ptr(struct dma_async_tx_descriptor *desc,
				      size_t *payload_len, size_t *max_len)
{
	int ret;

	if (!desc)
		return ERR_PTR(-EINVAL);

	ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE);
	if (ret)
		return ERR_PTR(ret);

	if (!desc->metadata_ops || !desc->metadata_ops->get_ptr)
		return ERR_PTR(-ENOTSUPP);

	return desc->metadata_ops->get_ptr(desc, payload_len, max_len);
}

Callers of dmaengine_desc_get_metadata_ptr(), such as axienet_dma_rx_cb() in
drivers/net/ethernet/xilinx/xilinx_axienet_main.c, check the returned pointer
with IS_ERR() before dereferencing it:

	app_metadata = dmaengine_desc_get_metadata_ptr(skbuf_dma->desc, &meta_len,
						       &meta_max_len);
	...
	if (IS_ERR(app_metadata)) {
		if (net_ratelimit())
			netdev_err(lp->ndev, "Failed to get RX metadata pointer\n");
		dev_kfree_skb_any(skb);
		lp->ndev->stats.rx_dropped++;
		goto rx_submit;
	}

	/* TODO: Derive app word index programmatically */
	rx_len = (app_metadata[LEN_APP] & 0xFFFF);

Because IS_ERR(NULL) is false, returning NULL when !seg bypasses the caller's
error check and leads to a NULL pointer dereference, while also mutating
*max_len and *payload_len on failure.

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

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

* Re: [PATCH] dmaengine: xilinx: Fix wild pointer dereference on empty segment list
  2026-10-23  7:10 ` sashiko-bot
@ 2026-10-27 19:34   ` Frank Li
  0 siblings, 0 replies; 3+ messages in thread
From: Frank Li @ 2026-10-27 19:34 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Li Ximo, dmaengine, vkoul, Frank.Li

On Fri, Oct 23, 2026 at 07:10:22AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] dmaengine: xilinx: NULL return in xilinx_dma_get_metadata_ptr()
> --
>
> commit 5ff31a1fefdaf467f495be421ba38281e2cbd1a6
> Author: Wang Haoran <haoranwangsec@gmail.com>
>
> dmaengine: xilinx: Fix wild pointer dereference on empty segment list
>
> This commit guards against empty segment lists in the Xilinx DMA prep
> functions and in xilinx_dma_get_metadata_ptr() to avoid dereferencing wild
> pointers from list_first_entry().
>
> > diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> > index cffe7c6fa6405..07f52f8412b10 100644
> > --- a/drivers/dma/xilinx/xilinx_dma.c
> > +++ b/drivers/dma/xilinx/xilinx_dma.c
> > @@ -650,8 +650,11 @@ static void *xilinx_dma_get_metadata_ptr(struct dma_async_tx_descriptor *tx,
> >  	struct xilinx_axidma_tx_segment *seg;
> >
> >  	*max_len = *payload_len = sizeof(u32) * XILINX_DMA_NUM_APP_WORDS;
> > -	seg = list_first_entry(&desc->segments,
> > -			       struct xilinx_axidma_tx_segment, node);
> > +	seg = list_first_entry_or_null(&desc->segments,
> > +				       struct xilinx_axidma_tx_segment, node);
> > +	if (!seg)
> > +		return NULL;
>
> [Severity: High]
> Should xilinx_dma_get_metadata_ptr() return an ERR_PTR() (such as
> ERR_PTR(-EINVAL) or ERR_PTR(-ENODATA)) before modifying *max_len and
> *payload_len when desc->segments is empty, rather than returning NULL?
>
> The caller in drivers/dma/dmaengine.c uses the ERR_PTR() error convention and
> directly returns the result of metadata_ops->get_ptr():
>
> void *dmaengine_desc_get_metadata_ptr(struct dma_async_tx_descriptor *desc,
> 				      size_t *payload_len, size_t *max_len)
> {
> 	int ret;
>
> 	if (!desc)
> 		return ERR_PTR(-EINVAL);
>
> 	ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE);
> 	if (ret)
> 		return ERR_PTR(ret);
>
> 	if (!desc->metadata_ops || !desc->metadata_ops->get_ptr)
> 		return ERR_PTR(-ENOTSUPP);
>
> 	return desc->metadata_ops->get_ptr(desc, payload_len, max_len);
> }
>
> Callers of dmaengine_desc_get_metadata_ptr(), such as axienet_dma_rx_cb() in
> drivers/net/ethernet/xilinx/xilinx_axienet_main.c, check the returned pointer
> with IS_ERR() before dereferencing it:
>
> 	app_metadata = dmaengine_desc_get_metadata_ptr(skbuf_dma->desc, &meta_len,
> 						       &meta_max_len);
> 	...
> 	if (IS_ERR(app_metadata)) {
> 		if (net_ratelimit())
> 			netdev_err(lp->ndev, "Failed to get RX metadata pointer\n");
> 		dev_kfree_skb_any(skb);
> 		lp->ndev->stats.rx_dropped++;
> 		goto rx_submit;
> 	}
>
> 	/* TODO: Derive app word index programmatically */
> 	rx_len = (app_metadata[LEN_APP] & 0xFFFF);
>
> Because IS_ERR(NULL) is false, returning NULL when !seg bypasses the caller's
> error check and leads to a NULL pointer dereference, while also mutating
> *max_len and *payload_len on failure.

Make sense, please fix it.

Frank
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20261023065806.3175584-1-lixicaicai@gmail.com?part=1

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

end of thread, other threads:[~2026-10-27 19:34 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-23  6:58 [PATCH] dmaengine: xilinx: Fix wild pointer dereference on empty segment list Li Ximo
2026-10-23  7:10 ` sashiko-bot
2026-10-27 19:34   ` Frank Li

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