mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Robin Murphy <robin.murphy@arm.com>
To: Andrei-Edward Popa <andrei.popa105@yahoo.com>, m.szyprowski@samsung.com
Cc: iommu@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] dma-remap: fix dma_common_find_pages() page lookup for offsets
Date: Mon, 15 Dec 2025 10:52:40 +0000	[thread overview]
Message-ID: <60c8fd07-96f6-442d-9415-0e1226f1e0e6@arm.com> (raw)
In-Reply-To: <20251212200914.138310-1-andrei.popa105@yahoo.com>

On 2025-12-12 8:09 pm, Andrei-Edward Popa wrote:
> dma_common_find_pages() previously assumed that the CPU virtual address
> always pointed to the start of a DMA-coherent allocation. This fails when
> memory is allocated via dma_alloc_attrs() without DMA_ATTR_FORCE_CONTIGUOUS
> and then subdivided into smaller blocks using a gen_pool, relevant only
> when an IOMMU is enabled.
> 
> In such cases, userspace may request a mapping via dma_mmap_attrs()
> for a CPU address that is offset inside the original allocation. The
> previous code could return the wrong struct page pointer.
> 
> Example scenario:
> 
>    - Allocate a large DMA buffer with dma_alloc_attrs() (non-contiguous)
>    - Create a gen_pool using this buffer
>    - Take sub-allocations from the gen_pool
>    - Map the sub-allocations to userspace via dma_mmap_attrs()

That's where the bug is. If a driver wants to subdivide an allocation 
then it needs to keep track of what it's done, and handle mmap properly 
to offset the VMA relative to the original allocation before passing the 
request through. See the kerneldoc for dma_mmap_attrs():

  * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
  * @dma_addr: device-view address returned from dma_alloc_attrs
  * @size: size of memory originally requested in dma_alloc_attrs

"address returned from dma_alloc_attrs" does not mean "any arbitrary 
address within the bounds of the original address/size", it means 
exactly what it says, i.e. the original address.

Thanks
Robin.

>    - dma_common_find_pages() must return the correct struct page for the offset
> 
> This patch computes the page index relative to the vm_struct backing
> the DMA allocation:
> 
>      page_index = (vaddr - area->addr) >> PAGE_SHIFT
> 
> Bounds checks ensure the CPU address is within the vm_struct and
> page_index < area->nr_pages.
> 
> This ensures correct behavior for sub-allocated regions from gen_pool,
> without affecting allocations starting at the base address or allocations
> with DMA_ATTR_FORCE_CONTIGUOUS.
> 
> Signed-off-by: Andrei-Edward Popa <andrei.popa105@yahoo.com>
> ---
>   kernel/dma/remap.c | 15 ++++++++++++++-
>   1 file changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/dma/remap.c b/kernel/dma/remap.c
> index b7c1c0c92d0c..d27477e32ed8 100644
> --- a/kernel/dma/remap.c
> +++ b/kernel/dma/remap.c
> @@ -9,12 +9,25 @@
>   struct page **dma_common_find_pages(void *cpu_addr)
>   {
>   	struct vm_struct *area = find_vm_area(cpu_addr);
> +	unsigned long vaddr, area_vaddr;
> +	size_t page_index;
>   
>   	if (!area || !(area->flags & VM_DMA_COHERENT))
>   		return NULL;
>   	WARN(area->flags != VM_DMA_COHERENT,
>   	     "unexpected flags in area: %p\n", cpu_addr);
> -	return area->pages;
> +
> +	vaddr = (unsigned long)cpu_addr;
> +	area_vaddr = (unsigned long)area->addr;
> +	if (unlikely(vaddr < area_vaddr ||
> +		     vaddr >= area_vaddr + area->size))
> +		return NULL;
> +
> +	page_index = (vaddr - area_vaddr) >> PAGE_SHIFT;
> +	if (unlikely(page_index >= area->nr_pages))
> +		return NULL;
> +
> +	return &area->pages[page_index];
>   }
>   
>   /*


      parent reply	other threads:[~2025-12-15 10:52 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20251212200914.138310-1-andrei.popa105.ref@yahoo.com>
2025-12-12 20:09 ` Andrei-Edward Popa
2025-12-15  5:57   ` Christoph Hellwig
2025-12-15  8:13     ` Marek Szyprowski
2025-12-15 11:31       ` Robin Murphy
2025-12-15 20:49         ` Andrei-Edward Popa
2025-12-15 10:52   ` Robin Murphy [this message]

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=60c8fd07-96f6-442d-9415-0e1226f1e0e6@arm.com \
    --to=robin.murphy@arm.com \
    --cc=andrei.popa105@yahoo.com \
    --cc=iommu@lists.linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=m.szyprowski@samsung.com \
    /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

all inboxes | Powered by JetHome®