From: Fangyu Yu <[email protected]>

The FDT search loop in machine_kexec_prepare() reads sizeof(fdt) bytes
from segment[i].buf to identify the device tree, but it gates the read
on segment[i].memsz, which is the destination size in the next kernel.
kexec allows bufsz < memsz (the loaded image is zero-padded at the
destination), so a caller can craft a segment with bufsz=10 and
memsz=1MB:

        if (image->segment[i].memsz <= sizeof(fdt))   /* 1MB > 40, OK */
                continue;
        memcpy(&fdt, image->segment[i].buf, sizeof(fdt));  /* reads 40
                                                              from a 10-byte
                                                              kbuf */

For kexec_file_load (image->file_mode), the read walks 30 bytes past
the kernel-allocated kbuf. In the worst case the trailing bytes fall
in an unmapped guard page and the read faults the kernel; in the
common case the read returns garbage which fdt_check_header() rejects
and the loop continues. The plain kexec_load path is shielded by
copy_from_user(), which validates the read against the user mapping.

Replace the memsz check with the bufsz check, which is the right
bound for the read site.

Fixes: fba8a8674f68 ("RISC-V: Add kexec support")
Signed-off-by: Fangyu Yu <[email protected]>
---
 arch/riscv/kernel/machine_kexec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/machine_kexec.c 
b/arch/riscv/kernel/machine_kexec.c
index ea6794c9f4c2..e6e179cffc44 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -38,7 +38,7 @@ machine_kexec_prepare(struct kimage *image)
 
        /* Find the Flattened Device Tree and save its physical address */
        for (i = 0; i < image->nr_segments; i++) {
-               if (image->segment[i].memsz <= sizeof(fdt))
+               if (image->segment[i].bufsz < sizeof(fdt))
                        continue;
 
                if (image->file_mode)
-- 
2.50.1


Reply via email to