arm64: kexec_file: Stop using the Image text_offset
PATCH v8 1/1 arm64: kexec_file: Stop using the Image text_offset
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.
---
v2:
- Split out from the patch set.
- Link to v7: https://lore.kernel.org/all/[email protected]/
--- arch/arm64/kernel/kexec_image.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
arch/arm64/kernel/kexec_image.c +8 -5
@@ -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",
Signature · 1 line
2.34.1
Catalin Marinas
maintainerQuoted 7 lines · Jinjie Ruan
image_load()addstext_offsettokernel_segment->memand subtracts it fromkernel_segment->memsz. For CMA backed segments this breaks the load path: the payload is copied topage_address(cma), which is the CMA base, whileimage->startis 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.
Quoted 5 lines
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: removeTEXT_OFFSETrandomization")
This commit only removed the randomisation. The one you want mentioned here is cfa7ede20f13 ("arm64: set TEXT_OFFSET to 0x0 in preparation for removing it entirely"). Although this removing never happened (see more below).
Quoted 29 lines
TEXT_OFFSETis always zero. This has been upstream since v5.8, so no LTS kernel carries a non-zerotext_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]>Fixes 07d24902977e ("kexec: enable CMA based contiguous allocation")Suggested-by Mike Rapoport <[email protected]>Signed-off-by Jinjie Ruan <[email protected]>---
v2:
- Split out from the patch set.
- Link to v7: https://lore.kernel.org/all/[email protected]/--- arch/arm64/kernel/kexec_image.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)arch/arm64/kernel/kexec_image.c +0
-0@@ -80,12 +80,17 @@ static void *image_load(struct kimage *image, kbuf.bufsz = kernel_len; kbuf.mem =KEXEC_BUF_MEM_UNKNOWN ;
arch/arm64/kernel/kexec_image.c static void *image_load(struct kimage *image, · line 91
Quoted 10 lines
arch/arm64/kernel/kexec_image.c +8
-0kbuf.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 ); + }
If it's only CMA getting it wrong, can we not just set image->no_cma = true here and continue as normal?
While text_offset is 0 now, I don't think we concluded it should be deprecated. There was a recent push back on the attempt to document the always 0 behaviour:
https://lore.kernel.org/all/[email protected]/
Signature · 1 line
Catalin
Hi Catalin,
Quoted 12 lines · Catalin Marinas
Quoted 11 lines · Jinjie Ruan
image_load()addstext_offsettokernel_segment->memand subtracts it fromkernel_segment->memsz. For CMA backed segments this breaks the load path: the payload is copied topage_address(cma), which is the CMA base, whileimage->startis 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.
Quoted 6 lines
Quoted 1 line
Since commit
751c263bb74f("arm64: removeTEXT_OFFSETrandomization")This commit only removed the randomisation. The one you want mentioned here is
cfa7ede20f13("arm64: setTEXT_OFFSETto0x0in preparation for removing it entirely"). Although this removing never happened (see more below).
You are right! we should correct the commit.
Quoted 35 lines
Quoted 35 lines
TEXT_OFFSETis always zero. This has been upstream since v5.8, so no LTS kernel carries a non-zerotext_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]>Fixes 07d24902977e ("kexec: enable CMA based contiguous allocation")Suggested-by Mike Rapoport <[email protected]>Signed-off-by Jinjie Ruan <[email protected]>---
v2:
- Split out from the patch set.
- Link to v7: https://lore.kernel.org/all/[email protected]/--- arch/arm64/kernel/kexec_image.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)arch/arm64/kernel/kexec_image.c +4
-0@@ -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. +*/
Quoted 9 lines
arch/arm64/kernel/kexec_image.c static void *image_load(struct kimage *image, · line 91
Quoted 5 lines
arch/arm64/kernel/kexec_image.c +4
-0text_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 ); + }If it's only CMA getting it wrong, can we not just set
image->no_cma= true here and continue as normal?
Yes, it also works.
I tested this cma problem on QEMU arm64 with cma=64M and an Image header whose text_offset is 0x80000.
- Without fix , it jump 512K past the CMA copy and never boot;
- With the fix, it loads from normal memory and the second kernel boots.
Quoted 3 lines
While
text_offsetis 0 now, I don't think we concluded it should be deprecated. There was a recent push back on the attempt to document the always 0 behaviour:
Thank you! I will fix it with your suggestion.
Best regards,
Jinjie