[PATCH v5 09/17] x86/crash: Fix massive out-of-bounds write on 32-bit Highmem
Jinjie Ruan <[email protected]>
| Newsgroups | gmane.linux.kernel |
|---|---|
| Message-ID | <20260918100442.3841135-10-ruanjinjie__28183.8853655913$1789727866$gmane$org@huawei.com> |
On 32-bit x86 systems with HIGHMEM, kmap_local_page() only maps a single 4KB page. However, the elfcorehdr segment can span several pages (up to hundreds of kilobytes). The original code blindly copies 'elfsz' bytes at once via memcpy_flushcache(), overwriting adjacent fixmap entries or critical virtual addresses. Fix this by copying the new elfcorehdr page by page. Cc: Thomas Gleixner <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Dave Hansen <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: "Mike Rapoport (Microsoft)" <[email protected]> Cc: Vishal Verma <[email protected]> Cc: Baoquan He <[email protected]> Cc: Chao Gao <[email protected]> Cc: Sean Christopherson <[email protected]> Cc: Eric DeVolder <[email protected]> Cc: Hari Bathini <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Sourabh Jain <[email protected]> Cc: [email protected] Fixes: ea53ad9cf73b ("x86/crash: add x86 crash hotplug support") Link: https://sashiko.dev/#/patchset/20260907125404.922123-1-ruanjinjie%40huawei.com Signed-off-by: Jinjie Ruan <[email protected]> --- arch/x86/kernel/crash.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index e681ec9cf1dc..3c9f4fbbe7ff 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -447,9 +447,10 @@ unsigned int arch_crash_get_elfcorehdr_size(void) */ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) { - void *elfbuf = NULL, *old_elfcorehdr; unsigned long mem, memsz; unsigned long elfsz = 0; + void *elfbuf = NULL; + unsigned long done; /* * As crash_prepare_elf64_headers() has already described all @@ -484,21 +485,20 @@ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) /* * Copy new elfcorehdr over the old elfcorehdr at destination. - */ - old_elfcorehdr = kmap_local_page(pfn_to_page(mem >> PAGE_SHIFT)); - if (!old_elfcorehdr) { - pr_err("mapping elfcorehdr segment failed\n"); - goto out; - } - - /* - * Temporarily invalidate the crash image while the - * elfcorehdr is updated. + * The segment is physically contiguous but can span several pages. + * On 32-bit Highmem architectures, kmap_local_page() maps only a + * single page at a time, so copy page by page. */ xchg(&kexec_crash_image, NULL); - memcpy_flushcache(old_elfcorehdr, elfbuf, elfsz); + for (done = 0; done < elfsz; ) { + size_t chunk = min_t(size_t, PAGE_SIZE, elfsz - done); + void *dst = kmap_local_page(pfn_to_page((mem + done) >> PAGE_SHIFT)); + + memcpy_flushcache(dst, elfbuf + done, chunk); + kunmap_local(dst); + done += chunk; + } xchg(&kexec_crash_image, image); - kunmap_local(old_elfcorehdr); pr_debug("updated elfcorehdr\n"); out: -- 2.34.1