From: mina86@mina86.com (Michal Nazarewicz)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 2/2] ARM: dma-mapping: fix alloc/free for coherent + CMA + gfp=0
Date: Fri, 19 Feb 2016 14:50:52 +0100 [thread overview]
Message-ID: <xa1tio1kzu4j.fsf@mina86.com> (raw)
In-Reply-To: <1455869524-13874-2-git-send-email-rabin.vincent@axis.com>
On Fri, Feb 19 2016, Rabin Vincent wrote:
> Given a device which uses arm_coherent_dma_ops and on which
> dev_get_cma_area(dev) returns non-NULL, the following usage of the DMA
> API with gfp=0 results in a memory leak and memory corruption.
>
> p = dma_alloc_coherent(dev, sz, &dma, 0);
> if (p)
> dma_free_coherent(dev, sz, p, dma);
>
> The memory leak is because the alloc allocates using
> __alloc_simple_buffer() but the free attempts
> dma_release_from_contiguous(), which does not do free anything since the
> page is not in the CMA area.
>
> The memory corruption is because the free calls __dma_remap() on a page
> which is backed by only first level page tables. The
> apply_to_page_range() + __dma_update_pte() loop ends up interpreting the
> section mapping as the address to a second level page table and writing
> the new PTE to memory which is not used by page tables.
>
> We don't have access to the GFP flags used for allocation in the free
> function, so fix it by using the new in_cma() function to determine if a
> buffer was allocated with CMA, similar to how we check for
> __in_atomic_pool().
>
> Fixes: 21caf3a7 ("ARM: 8398/1: arm DMA: Fix allocation from CMA for coherent DMA")
> Signed-off-by: Rabin Vincent <rabin.vincent@axis.com>
> ---
> arch/arm/mm/dma-mapping.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index 0eca381..a4592c7 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -749,16 +749,16 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
> __dma_free_buffer(page, size);
> } else if (!is_coherent && __free_from_pool(cpu_addr, size)) {
> return;
> - } else if (!dev_get_cma_area(dev)) {
> - if (want_vaddr && !is_coherent)
> - __dma_free_remap(cpu_addr, size);
> - __dma_free_buffer(page, size);
> - } else {
> + } else if (in_cma(dev_get_cma_area(dev), page, size >> PAGE_SHIFT)) {
> /*
> * Non-atomic allocations cannot be freed with IRQs disabled
> */
> WARN_ON(irqs_disabled());
> __free_from_contiguous(dev, page, cpu_addr, size, want_vaddr);
> + } else {
> + if (want_vaddr && !is_coherent)
> + __dma_free_remap(cpu_addr, size);
> + __dma_free_buffer(page, size);
> }
> }
I haven?t looked closely at the code, but why not:
struct cma *cma =
if (!cma_release(dev_get_cma_area(dev), page, size >> PAGE_SHIFT)) {
// ... do whatever other non-CMA free
}
--
Best regards
Liege of Serenely Enlightened Majesty of Computer Science,
??? ?mina86? ?????? <mpn@google.com> <xmpp:mina86@jabber.org>
WARNING: multiple messages have this Message-ID (diff)
From: Michal Nazarewicz <mina86@mina86.com>
To: Rabin Vincent <rabin.vincent@axis.com>, linux@arm.linux.org.uk
Cc: akpm@linux-foundation.org, linux-arm-kernel@lists.infradead.org,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
Rabin Vincent <rabinv@axis.com>
Subject: Re: [PATCH 2/2] ARM: dma-mapping: fix alloc/free for coherent + CMA + gfp=0
Date: Fri, 19 Feb 2016 14:50:52 +0100 [thread overview]
Message-ID: <xa1tio1kzu4j.fsf@mina86.com> (raw)
In-Reply-To: <1455869524-13874-2-git-send-email-rabin.vincent@axis.com>
On Fri, Feb 19 2016, Rabin Vincent wrote:
> Given a device which uses arm_coherent_dma_ops and on which
> dev_get_cma_area(dev) returns non-NULL, the following usage of the DMA
> API with gfp=0 results in a memory leak and memory corruption.
>
> p = dma_alloc_coherent(dev, sz, &dma, 0);
> if (p)
> dma_free_coherent(dev, sz, p, dma);
>
> The memory leak is because the alloc allocates using
> __alloc_simple_buffer() but the free attempts
> dma_release_from_contiguous(), which does not do free anything since the
> page is not in the CMA area.
>
> The memory corruption is because the free calls __dma_remap() on a page
> which is backed by only first level page tables. The
> apply_to_page_range() + __dma_update_pte() loop ends up interpreting the
> section mapping as the address to a second level page table and writing
> the new PTE to memory which is not used by page tables.
>
> We don't have access to the GFP flags used for allocation in the free
> function, so fix it by using the new in_cma() function to determine if a
> buffer was allocated with CMA, similar to how we check for
> __in_atomic_pool().
>
> Fixes: 21caf3a7 ("ARM: 8398/1: arm DMA: Fix allocation from CMA for coherent DMA")
> Signed-off-by: Rabin Vincent <rabin.vincent@axis.com>
> ---
> arch/arm/mm/dma-mapping.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index 0eca381..a4592c7 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -749,16 +749,16 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
> __dma_free_buffer(page, size);
> } else if (!is_coherent && __free_from_pool(cpu_addr, size)) {
> return;
> - } else if (!dev_get_cma_area(dev)) {
> - if (want_vaddr && !is_coherent)
> - __dma_free_remap(cpu_addr, size);
> - __dma_free_buffer(page, size);
> - } else {
> + } else if (in_cma(dev_get_cma_area(dev), page, size >> PAGE_SHIFT)) {
> /*
> * Non-atomic allocations cannot be freed with IRQs disabled
> */
> WARN_ON(irqs_disabled());
> __free_from_contiguous(dev, page, cpu_addr, size, want_vaddr);
> + } else {
> + if (want_vaddr && !is_coherent)
> + __dma_free_remap(cpu_addr, size);
> + __dma_free_buffer(page, size);
> }
> }
I haven’t looked closely at the code, but why not:
struct cma *cma =
if (!cma_release(dev_get_cma_area(dev), page, size >> PAGE_SHIFT)) {
// ... do whatever other non-CMA free
}
--
Best regards
Liege of Serenely Enlightened Majesty of Computer Science,
ミハウ “mina86” ナザレヴイツ <mpn@google.com> <xmpp:mina86@jabber.org>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
WARNING: multiple messages have this Message-ID (diff)
From: Michal Nazarewicz <mina86@mina86.com>
To: Rabin Vincent <rabin.vincent@axis.com>, linux@arm.linux.org.uk
Cc: akpm@linux-foundation.org, linux-arm-kernel@lists.infradead.org,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
Rabin Vincent <rabinv@axis.com>
Subject: Re: [PATCH 2/2] ARM: dma-mapping: fix alloc/free for coherent + CMA + gfp=0
Date: Fri, 19 Feb 2016 14:50:52 +0100 [thread overview]
Message-ID: <xa1tio1kzu4j.fsf@mina86.com> (raw)
In-Reply-To: <1455869524-13874-2-git-send-email-rabin.vincent@axis.com>
On Fri, Feb 19 2016, Rabin Vincent wrote:
> Given a device which uses arm_coherent_dma_ops and on which
> dev_get_cma_area(dev) returns non-NULL, the following usage of the DMA
> API with gfp=0 results in a memory leak and memory corruption.
>
> p = dma_alloc_coherent(dev, sz, &dma, 0);
> if (p)
> dma_free_coherent(dev, sz, p, dma);
>
> The memory leak is because the alloc allocates using
> __alloc_simple_buffer() but the free attempts
> dma_release_from_contiguous(), which does not do free anything since the
> page is not in the CMA area.
>
> The memory corruption is because the free calls __dma_remap() on a page
> which is backed by only first level page tables. The
> apply_to_page_range() + __dma_update_pte() loop ends up interpreting the
> section mapping as the address to a second level page table and writing
> the new PTE to memory which is not used by page tables.
>
> We don't have access to the GFP flags used for allocation in the free
> function, so fix it by using the new in_cma() function to determine if a
> buffer was allocated with CMA, similar to how we check for
> __in_atomic_pool().
>
> Fixes: 21caf3a7 ("ARM: 8398/1: arm DMA: Fix allocation from CMA for coherent DMA")
> Signed-off-by: Rabin Vincent <rabin.vincent@axis.com>
> ---
> arch/arm/mm/dma-mapping.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index 0eca381..a4592c7 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -749,16 +749,16 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
> __dma_free_buffer(page, size);
> } else if (!is_coherent && __free_from_pool(cpu_addr, size)) {
> return;
> - } else if (!dev_get_cma_area(dev)) {
> - if (want_vaddr && !is_coherent)
> - __dma_free_remap(cpu_addr, size);
> - __dma_free_buffer(page, size);
> - } else {
> + } else if (in_cma(dev_get_cma_area(dev), page, size >> PAGE_SHIFT)) {
> /*
> * Non-atomic allocations cannot be freed with IRQs disabled
> */
> WARN_ON(irqs_disabled());
> __free_from_contiguous(dev, page, cpu_addr, size, want_vaddr);
> + } else {
> + if (want_vaddr && !is_coherent)
> + __dma_free_remap(cpu_addr, size);
> + __dma_free_buffer(page, size);
> }
> }
I haven’t looked closely at the code, but why not:
struct cma *cma =
if (!cma_release(dev_get_cma_area(dev), page, size >> PAGE_SHIFT)) {
// ... do whatever other non-CMA free
}
--
Best regards
Liege of Serenely Enlightened Majesty of Computer Science,
ミハウ “mina86” ナザレヴイツ <mpn@google.com> <xmpp:mina86@jabber.org>
next prev parent reply other threads:[~2016-02-19 13:50 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-19 8:12 [PATCH 1/2] mm: cma: split out in_cma check to separate function Rabin Vincent
2016-02-19 8:12 ` Rabin Vincent
2016-02-19 8:12 ` Rabin Vincent
2016-02-19 8:12 ` [PATCH 2/2] ARM: dma-mapping: fix alloc/free for coherent + CMA + gfp=0 Rabin Vincent
2016-02-19 8:12 ` Rabin Vincent
2016-02-19 8:12 ` Rabin Vincent
2016-02-19 13:50 ` Michal Nazarewicz [this message]
2016-02-19 13:50 ` Michal Nazarewicz
2016-02-19 13:50 ` Michal Nazarewicz
2016-02-23 15:30 ` Rabin Vincent
2016-02-23 15:30 ` Rabin Vincent
2016-02-23 15:30 ` Rabin Vincent
2016-02-19 14:06 ` Russell King - ARM Linux
2016-02-19 14:06 ` Russell King - ARM Linux
2016-02-19 14:06 ` Russell King - ARM Linux
2016-02-23 15:23 ` Rabin Vincent
2016-02-23 15:23 ` Rabin Vincent
2016-02-23 15:23 ` Rabin Vincent
2016-02-19 13:46 ` [PATCH 1/2] mm: cma: split out in_cma check to separate function Michal Nazarewicz
2016-02-19 13:46 ` Michal Nazarewicz
2016-02-19 13:46 ` Michal Nazarewicz
2016-02-19 21:23 ` Andrew Morton
2016-02-19 21:23 ` Andrew Morton
2016-02-19 21:23 ` Andrew Morton
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=xa1tio1kzu4j.fsf@mina86.com \
--to=mina86@mina86.com \
--cc=linux-arm-kernel@lists.infradead.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.