Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kexec_core: remove superfluous page offset handling in segment loading

During kexec_segment loading, when copying the content of the segment
(i.e. kexec_segment::kbuf or kexec_segment::buf) to its associated pages,
kimage_load_{cma,normal,crash}_segment handle the case where the physical
address of the segment is not page aligned, e.g. in
kimage_load_normal_segment:

page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
// ...
ptr = kmap_local_page(page);
// ...
ptr += maddr & ~PAGE_MASK;
mchunk = min_t(size_t, mbytes,
PAGE_SIZE - (maddr & ~PAGE_MASK));
// ^^^^ Non page-aligned segments handled here ^^^
// ...
if (image->file_mode)
memcpy(ptr, kbuf, uchunk);
else
result = copy_from_user(ptr, buf, uchunk);

(similar logic is present in kimage_load_{cma,crash}_segment).

This is actually not needed because, prior to their loading, all
kexec_segments first go through a vetting step in
`sanity_check_segment_list`, which rejects any segment that is not
page-aligned:

for (i = 0; i < nr_segments; i++) {
unsigned long mstart, mend;
mstart = image->segment[i].mem;
mend = mstart + image->segment[i].memsz;
// ...
if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK))
return -EADDRNOTAVAIL;
// ...
}

In case `sanity_check_segment_list` finds a non-page aligned the whole
kexec load is aborted and no segment is loaded.

This means that `kimage_load_{cma,normal,crash}_segment` never actually
have to handle non page-aligned segments and `(maddr & ~PAGE_MASK) == 0`
is always true no matter if the segment is coming from a file (i.e.
`kexec_file_load` syscall), from a user-space buffer (i.e. `kexec_load`
syscall) or created by the kernel through `kexec_add_buffer`. In the
latter case, `kexec_add_buffer` actually enforces the page alignment:

/* Ensure minimum alignment needed for segments. */
kbuf->memsz = ALIGN(kbuf->memsz, PAGE_SIZE);
kbuf->buf_align = max(kbuf->buf_align, PAGE_SIZE);

[jbouron@amazon.com: v3]
Link: https://lkml.kernel.org/r/20251024155009.39502-1-jbouron@amazon.com
Link: https://lkml.kernel.org/r/20250929160220.47616-1-jbouron@amazon.com
Signed-off-by: Justinien Bouron <jbouron@amazon.com>
Reviewed-by: Gunnar Kudrjavets <gunnarku@amazon.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: Alexander Graf <graf@amazon.com>
Cc: Marcos Paulo de Souza <mpdesouza@suse.com>
Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Yan Zhao <yan.y.zhao@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Justinien Bouron and committed by
Andrew Morton
6a2e57ad 8a7d5884

+3 -12
+3 -12
kernel/kexec_core.c
··· 742 742 struct kexec_segment *segment = &image->segment[idx]; 743 743 struct page *cma = image->segment_cma[idx]; 744 744 char *ptr = page_address(cma); 745 - unsigned long maddr; 746 745 size_t ubytes, mbytes; 747 746 int result = 0; 748 747 unsigned char __user *buf = NULL; ··· 753 754 buf = segment->buf; 754 755 ubytes = segment->bufsz; 755 756 mbytes = segment->memsz; 756 - maddr = segment->mem; 757 757 758 758 /* Then copy from source buffer to the CMA one */ 759 759 while (mbytes) { 760 760 size_t uchunk, mchunk; 761 761 762 - ptr += maddr & ~PAGE_MASK; 763 - mchunk = min_t(size_t, mbytes, 764 - PAGE_SIZE - (maddr & ~PAGE_MASK)); 762 + mchunk = min_t(size_t, mbytes, PAGE_SIZE); 765 763 uchunk = min(ubytes, mchunk); 766 764 767 765 if (uchunk) { ··· 780 784 } 781 785 782 786 ptr += mchunk; 783 - maddr += mchunk; 784 787 mbytes -= mchunk; 785 788 786 789 cond_resched(); ··· 834 839 ptr = kmap_local_page(page); 835 840 /* Start with a clear page */ 836 841 clear_page(ptr); 837 - ptr += maddr & ~PAGE_MASK; 838 - mchunk = min_t(size_t, mbytes, 839 - PAGE_SIZE - (maddr & ~PAGE_MASK)); 842 + mchunk = min_t(size_t, mbytes, PAGE_SIZE); 840 843 uchunk = min(ubytes, mchunk); 841 844 842 845 if (uchunk) { ··· 897 904 } 898 905 arch_kexec_post_alloc_pages(page_address(page), 1, 0); 899 906 ptr = kmap_local_page(page); 900 - ptr += maddr & ~PAGE_MASK; 901 - mchunk = min_t(size_t, mbytes, 902 - PAGE_SIZE - (maddr & ~PAGE_MASK)); 907 + mchunk = min_t(size_t, mbytes, PAGE_SIZE); 903 908 uchunk = min(ubytes, mchunk); 904 909 if (mchunk > uchunk) { 905 910 /* Zero the trailing part of the page */