Thread (43 messages) 43 messages, 5 authors, 11h ago

Re: [PATCH v6 09/14] x86/crash: Fix massive out-of-bounds write on 32-bit Highmem

flat view

From: Jinjie Ruan <hidden>
Date: 2026-10-21 08:28:45
Also in: driver-core, kexec, lkml, loongarch


在 2026/10/20 16:09, Mike Rapoport 写道:
Hi Jinjie,
quoted
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.
Yes
quoted
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
Hi Mike,

x86 32-bit doesn't support memory hotplug, and NR_CPUS is capped at 8.

config NR_CPUS_RANGE_END
    int
    depends on X86_32
    default    8 if  SMP
    default    1 if !SMP

According to the elf header size calculation in
crash_prepare_elf64_headers():

- nr_phdr = num_possible_cpus() + nr_mem_ranges + 2
- sizeof(Elf64_Ehdr) = 64
- sizeof(Elf64_Phdr) = 56

so:
    elf_sz = 64 + (num_possible_cpus() + nr_mem_ranges + 2) * 56

To exceed 4K:

    64 + (num_possible_cpus() + nr_ranges + 2) * 56 > 4096


So we'd need at least 60+ RAM ranges, which seems unlikely on real
hardware without memory hotplug. I think this problem can't actually be
triggered in practice, so we can safely drop this patch.
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.
-- 
Best regards,
Jinjie

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help