[PATCH 3/4] mm/cma: reject CMA areas that overlap the kernel image
From: Radhey Shyam Pandey
Date: Tue Nov 03 2026 - 12:19:30 EST
cma_init_reserved_mem() takes a base chosen by its caller and only requires
that the range already be reserved, so an overlap with the kernel image is
indistinguishable from the normal case. cma_activate_area() then clears
PageReserved on those pages and frees them into MIGRATE_CMA, overriding the
memblock_reserve() of [_text, _end), so live kernel text reaches userspace.
kexec reached this until the fix this series builds on; a device tree
placing a shared-dma-pool over where the bootloader loaded the kernel still
can. Reject the overlap rather than let such a caller corrupt the kernel.
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xxxxxxx>
---
Changes since RFC:
- Drop Pratyush reviewed-by tag as there were few changes.
- Trim the commit description.
- Drop the redundant comment as suggested by Mike.
- cma_overlaps_kernel_image() is kept as helpers in asm-generic/sections.h
are virtual-address helpers.
---
mm/cma.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/mm/cma.c b/mm/cma.c
index 9c53b2b70dc8..3231a53161cd 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -31,6 +31,8 @@
#include <linux/kmemleak.h>
#include <trace/events/cma.h>
+#include <asm/sections.h>
+
#include "internal.h"
#include "cma.h"
#include "mm_init.h"
@@ -68,6 +70,16 @@ bool cma_has_dynamic_base(const struct cma *cma)
return test_bit(CMA_DYNAMIC_BASE, &cma->flags);
}
+static bool cma_overlaps_kernel_image(phys_addr_t base, phys_addr_t size)
+{
+ phys_addr_t end;
+
+ if (check_add_overflow(base, size, &end))
+ return true;
+
+ return base < __pa_symbol(_end) && __pa_symbol(_text) < end;
+}
+
static unsigned long cma_bitmap_aligned_mask(const struct cma *cma,
unsigned int align_order)
{
@@ -295,6 +307,15 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
if (!size || !memblock_is_region_reserved(base, size))
return -EINVAL;
+ if (cma_overlaps_kernel_image(base, size)) {
+ phys_addr_t text = __pa_symbol(_text);
+ phys_addr_t end = __pa_symbol(_end);
+
+ pr_err("area %s (%pa, size %pa) overlaps kernel image [%pa-%pa]\n",
+ name ?: "(unnamed)", &base, &size, &text, &end);
+ return -EBUSY;
+ }
+
/*
* CMA uses CMA_MIN_ALIGNMENT_BYTES as alignment requirement which
* needs pageblock_order to be initialized. Let's enforce it.
--
2.44.4