image_load() adds text_offset to kernel_segment->mem and subtracts it
from kernel_segment->memsz.  For CMA backed segments this breaks the
load path: the payload is copied to page_address(cma), which is the CMA
base, while image->start is set to the adjusted address, so kexec jumps
into the middle of the kernel.  kimage_map_segment() has the same
mismatch when a segment has been moved.

The adjusted memsz also breaks the release path: the CMA pages are
freed using segment->memsz >> PAGE_SHIFT, which is fewer than were
allocated, leaking the tail of the allocation.

Since commit 751c263bb74f ("arm64: remove TEXT_OFFSET randomization")
TEXT_OFFSET is always zero.  This has been upstream since v5.8, so no
LTS kernel carries a non-zero text_offset.  Drop the adjustment and
reject images with a non-zero value instead of booting them from a
wrong address.  With the adjustment gone, segments stay at their CMA
base and the release size matches the allocation.

Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Mike Rapoport <[email protected]>
Link: https://lore.kernel.org/all/[email protected]/
Link: https://lore.kernel.org/all/[email protected]/
Fixes: 07d24902977e ("kexec: enable CMA based contiguous allocation")
Suggested-by: Mike Rapoport <[email protected]>
Signed-off-by: Jinjie Ruan <[email protected]>
---
 arch/arm64/kernel/kexec_image.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index b8d0fb0a9daf..74d24c8aa2fa 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -80,12 +80,17 @@ static void *image_load(struct kimage *image,
        kbuf.bufsz = kernel_len;
        kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
        kbuf.memsz = le64_to_cpu(h->image_size);
+       /*
+        * Pre-v5.8 images carry a non-zero text_offset, which is no longer
+        * honored; reject them instead of loading them at a wrong address.
+        */
        text_offset = le64_to_cpu(h->text_offset);
+       if (text_offset) {
+               pr_err("Unsupported Image text_offset 0x%lx\n", text_offset);
+               return ERR_PTR(-ENOEXEC);
+       }
        kbuf.buf_align = MIN_KIMG_ALIGN;
 
-       /* Adjust kernel segment with TEXT_OFFSET */
-       kbuf.memsz += text_offset;
-
        kernel_segment_number = image->nr_segments;
 
        /*
@@ -117,8 +122,6 @@ static void *image_load(struct kimage *image,
        }
 
        kernel_segment = &image->segment[kernel_segment_number];
-       kernel_segment->mem += text_offset;
-       kernel_segment->memsz -= text_offset;
        image->start = kernel_segment->mem;
 
        kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
-- 
2.34.1


Reply via email to