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

Yes

> 
>> 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 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


Reply via email to