Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

of/kexec: Fix reading 32-bit "linux,initrd-{start,end}" values

"linux,initrd-start" and "linux,initrd-end" can be 32-bit values even on
a 64-bit platform. Ideally, the size should be based on
'#address-cells', but that has never been enforced in the kernel's FDT
boot parsing code (early_init_dt_check_for_initrd()). Bootloader
behavior is known to vary. For example, kexec always writes these as
64-bit. The result of incorrectly reading 32-bit values is most likely
the reserved memory for the original initrd will still be reserved
for the new kernel. The original arm64 equivalent of this code failed to
release the initrd reserved memory in *all* cases.

Use of_read_number() to mirror the early_init_dt_check_for_initrd()
code.

Fixes: b30be4dc733e ("of: Add a common kexec FDT setup function")
Cc: stable@vger.kernel.org
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Link: https://lore.kernel.org/r/20221128202440.1411895-1-robh@kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>

+5 -5
+5 -5
drivers/of/kexec.c
··· 281 281 const char *cmdline, size_t extra_fdt_size) 282 282 { 283 283 void *fdt; 284 - int ret, chosen_node; 284 + int ret, chosen_node, len; 285 285 const void *prop; 286 286 size_t fdt_size; 287 287 ··· 324 324 goto out; 325 325 326 326 /* Did we boot using an initrd? */ 327 - prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL); 327 + prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", &len); 328 328 if (prop) { 329 329 u64 tmp_start, tmp_end, tmp_size; 330 330 331 - tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop)); 331 + tmp_start = of_read_number(prop, len / 4); 332 332 333 - prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", NULL); 333 + prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", &len); 334 334 if (!prop) { 335 335 ret = -EINVAL; 336 336 goto out; 337 337 } 338 338 339 - tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop)); 339 + tmp_end = of_read_number(prop, len / 4); 340 340 341 341 /* 342 342 * kexec reserves exact initrd size, while firmware may