Re: [PATCH v6 09/14] x86/crash: Fix massive out-of-bounds write on 32-bit Highmem
flat view
From: Mike Rapoport <rppt@kernel.org>
Date: 2026-10-20 08:10:52
Also in:
driver-core, kexec, lkml, loongarch
Hi Jinjie,
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.
This is independed of other fixes and can be sent as a separate x86b fix.
quoted hunk ↗ jump to hunk
Cc: Thomas Gleixner <tglx@kernel.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: "Mike Rapoport (Microsoft)" <rppt@kernel.org> Cc: Vishal Verma <vishal.l.verma@intel.com> Cc: Baoquan He <baoquan.he@linux.dev> Cc: Chao Gao <redacted> Cc: Sean Christopherson <seanjc@google.com> Cc: Eric DeVolder <redacted> Cc: Hari Bathini <hbathini@linux.ibm.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Sourabh Jain <redacted> Cc: stable@vger.kernel.org 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 <redacted> --- 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 e681ec9cf1dc8..3c9f4fbbe7ff0 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; + }
HIGMEM is only enabled on 32-bit and there elfsz cannot be "massive" because it is the size of the headers just built for the CPUs and RAM ranges actually present, not the large memsz reserved for hotplug. On x86_32 (NR_CPUS <= 64) that is a few KiB at most. Also, crashkernel is capped at CRASH_ADDR_HIGH_MAX = SZ_512M on X86_32, which is below the default lowmem limit. For lowmem pages, kmap_local_page() returns the contiguous direct-map address, so the old code was already fine. So the overflow needs the crash region to be in highmem, either through crashkernel=size@offset above lowmem or through a large vmalloc= setting, and an elfcorehdr larger than one page. It is still worth fixing, but please drop "massive" from the subject. The changelog should also mention the conditions when this could happen. -- Sincerely yours, Mike.