Skip to content

Commit

Permalink
of/kexec: Fix reading 32-bit "linux,initrd-{start,end}" values
Browse files Browse the repository at this point in the history
commit e553ad8 upstream.

"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: b30be4d ("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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
robherring authored and gregkh committed Jan 12, 2023
1 parent 7eddcdb commit 4a19f48
Showing 1 changed file with 5 additions and 5 deletions.
10 changes: 5 additions & 5 deletions drivers/of/kexec.c
Expand Up @@ -284,7 +284,7 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
const char *cmdline, size_t extra_fdt_size)
{
void *fdt;
int ret, chosen_node;
int ret, chosen_node, len;
const void *prop;
size_t fdt_size;

Expand Down Expand Up @@ -327,19 +327,19 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
goto out;

/* Did we boot using an initrd? */
prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL);
prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", &len);
if (prop) {
u64 tmp_start, tmp_end, tmp_size;

tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop));
tmp_start = of_read_number(prop, len / 4);

prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", NULL);
prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", &len);
if (!prop) {
ret = -EINVAL;
goto out;
}

tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop));
tmp_end = of_read_number(prop, len / 4);

/*
* kexec reserves exact initrd size, while firmware may
Expand Down

0 comments on commit 4a19f48

Please sign in to comment.