[PATCH v15 07/23] arm64: kexec_file: Fix CMA page leaks during segment placement retry loops

From: Jinjie Ruan

Date: Mon Jun 01 2026 - 06:04:09 EST


Sashiko AI code review pointed out, during arm64 kexec image placement
retry loops in image_load(), the loader repeatedly attempts to find
a suitable memory hole for the kernel and its associated segments
(initrd, dtb, etc.). When a placement attempt fails midway, the core
framework rolls back `image->nr_segments` to its initial state to purge
the failed segments logically.

However, this truncation causes a severe background memory leak. Any CMA
pages successfully allocated via kexec_add_buffer() during the failed
attempt are recorded in the `image->segment_cma` array. Since
the subsequent global kimage_free_cma() cleanup only iterates up to
the truncated (smaller) `nr_segments` boundary, these allocated CMA pages
outside the new boundary become completely orphaned and permanently leaked.

Fix this by leverage the newly introduced generic kexec_free_segment_cma()
helper to execute fine-grained memory reclamation before any truncation
occurs:

1. In image_load(), explicitly invoke kexec_free_segment_cma() to release
the CMA buffer allocated for the current failed kernel segment before
decrementing `image->nr_segments`.

2. In the error path of load_other_segments(), iterate backward from the
failed segment index down to `orig_segments`, sequentially freeing each
orphan CMA segment allocation before restoring the initial segment
count.

This guarantees that all temporary CMA pages allocated during placement
failures are cleanly returned to the contiguous memory allocator,
eliminating silent background memory leaks across all retry paths.

Cc: Catalin Marinas <catalin.marinas@xxxxxxx>
Cc: Will Deacon <will@xxxxxxxxxx>
Cc: Breno Leitao <leitao@xxxxxxxxxx>
Cc: Pratyush Yadav <pratyush@xxxxxxxxxx>
Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Cc: Yeoreum Yun <yeoreum.yun@xxxxxxx>
Cc: Kees Cook <kees@xxxxxxxxxx>
Cc: "Rob Herring (Arm)" <robh@xxxxxxxxxx>
Cc: Baoquan He <bhe@xxxxxxxxxx>
Cc: Coiby Xu <coxu@xxxxxxxxxx>
Cc: Alexander Graf <graf@xxxxxxxxxx>
Cc: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
Fixes: 07d24902977e4 ("kexec: enable CMA based contiguous allocation")
Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
arch/arm64/kernel/kexec_image.c | 1 +
arch/arm64/kernel/machine_kexec_file.c | 5 ++++-
2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index b70f4df15a1a..ffcb7f9075e6 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -107,6 +107,7 @@ static void *image_load(struct kimage *image,
* We couldn't find space for the other segments; erase the
* kernel segment and try the next available hole.
*/
+ kexec_free_segment_cma(image, kernel_segment_number);
image->nr_segments -= 1;
kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index e31fabed378a..13c247c28866 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -195,7 +195,10 @@ int load_other_segments(struct kimage *image,
return 0;

out_err:
- image->nr_segments = orig_segments;
+ while (image->nr_segments > orig_segments) {
+ kexec_free_segment_cma(image, image->nr_segments - 1);
+ image->nr_segments--;
+ }
kvfree(dtb);
return ret;
}
--
2.34.1