Re: [PATCH v3 3/3] LoongArch: Avoid initrd overlap during kernel relocation
From: Huacai Chen
Date: Wed Apr 29 2026 - 03:40:33 EST
Hi, Rui,
On Wed, Apr 29, 2026 at 1:14 PM WANG Rui <r@xxxxxx> wrote:
>
> Validate the relocation address against the initrd region specified
> via "initrd=" or "initrdmem=" on the command line. Reject relocation
> targets that overlap the initrd to prevent memory corruption during
> early boot.
>
> Signed-off-by: WANG Rui <r@xxxxxx>
> ---
> arch/loongarch/kernel/relocate.c | 45 ++++++++++++++++++++++++++++++++
> 1 file changed, 45 insertions(+)
>
> diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
> index c36604a81d08..c303c0be8f06 100644
> --- a/arch/loongarch/kernel/relocate.c
> +++ b/arch/loongarch/kernel/relocate.c
> @@ -214,14 +214,59 @@ static inline void __init *determine_relocation_address(void)
> return RELOCATED_KASLR(destination);
> }
>
> +static unsigned long __init try_get_initrd(unsigned long *size)
Rename to determine_initrd_address() can keep consistency.
> +{
> + unsigned long start = 0;
> + unsigned int key_length;
It's type should be "unsigned long" because strstr() returns "unsigned long".
Huacai
> + const char *key;
> + char *p;
> +
> + key = "initrd=";
> + key_length = strlen(key);
> + p = strstr(boot_command_line, key);
> +
> + if (!p) {
> + key = "initrdmem=";
> + key_length = strlen(key);
> + p = strstr(boot_command_line, key);
> + }
> +
> + if (p == boot_command_line || (p > boot_command_line && *(p - 1) == ' ')) {
> + char *endp;
> +
> + p += key_length;
> + start = memparse(p, &endp);
> + if (*endp == ',')
> + *size = memparse(endp + 1, NULL);
> + }
> +
> + return start;
> +}
> +
> static inline int __init relocation_addr_valid(void *location_new)
> {
> + unsigned long initrd_start;
> + unsigned long initrd_size = 0;
> +
> if ((unsigned long)location_new & 0x00000ffff)
> return 0; /* Inappropriately aligned new location */
>
> if ((unsigned long)location_new < (unsigned long)_end)
> return 0; /* New location overlaps original kernel */
>
> + initrd_start = try_get_initrd(&initrd_size);
> + if (initrd_start && initrd_size) {
> + unsigned long kernel_start;
> + unsigned long kernel_size;
> +
> + kernel_start = PHYSADDR(location_new);
> + kernel_size = (unsigned long)_end - (unsigned long)_text;
> +
> + if (kernel_start < (initrd_start + initrd_size) &&
> + initrd_start < (kernel_start + kernel_size))
> + return 0; /* Initrd overlaps kernel */
> + }
> +
> return 1;
> }
> #endif
> --
> 2.54.0
>