[PATCH v4 3/3] LoongArch: Avoid initrd overlap during kernel relocation
WANG Rui <[email protected]> Wed, 29 Apr 2026 20:03:00 +0800
| Newsgroups | org.kernel.vger.linux-efi,dev.linux.lists.loongarch,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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. Acked-by: Ard Biesheuvel <[email protected]> Signed-off-by: WANG Rui <[email protected]> --- 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..721b982f194b 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 determine_initrd_address(unsigned long *size) +{ + unsigned long start = 0; + unsigned long key_length; + 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 = determine_initrd_address(&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