There is a race condition between the kexec_load() system call (crash kernel loading path) and memory hotplug operations that can lead to buffer overflow and potential kernel crash.
During prepare_elf_headers(), the following steps occur: 1. get_nr_ram_ranges_callback() queries current System RAM memory ranges 2. Allocates buffer based on queried count 3. prepare_elf64_ram_headers_callback() populates ranges from memblock If memory hotplug occurs between step 1 and step 3, the number of ranges can increase, causing out-of-bounds write when populating cmem->ranges[]. This happens because kexec_load() uses kexec_trylock (atomic_t) while memory hotplug uses device_hotplug_lock (mutex), so they don't serialize with each other. While this works today because RISC-V server hardware with hotplug support is still rare and most deployments use fixed memory configurations (e.g., QEMU virt machine), it is technically fragile. So add bounds checking in prepare_elf64_ram_headers_callback() to prevent out-of-bounds (OOB) access. No functional change for current RISC-V deployments, but makes the code robust against future hotplug-capable platforms. Cc: Paul Walmsley <[email protected]> Cc: Palmer Dabbelt <[email protected]> Cc: Albert Ou <[email protected]> Cc: Alexandre Ghiti <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Fixes: 8acea455fafa ("RISC-V: Support for kexec_file on panic") Reviewed-by: Guo Ren <[email protected]> Signed-off-by: Jinjie Ruan <[email protected]> --- arch/riscv/kernel/machine_kexec_file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c index 3f7766057cac..773a1cba8ba0 100644 --- a/arch/riscv/kernel/machine_kexec_file.c +++ b/arch/riscv/kernel/machine_kexec_file.c @@ -48,6 +48,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) { struct crash_mem *cmem = arg; + if (cmem->nr_ranges >= cmem->max_nr_ranges) + return -ENOMEM; + cmem->ranges[cmem->nr_ranges].start = res->start; cmem->ranges[cmem->nr_ranges].end = res->end; cmem->nr_ranges++; -- 2.34.1
