[PATCH v4 3/3] LoongArch: Avoid initrd overlap during kernel relocation

From: WANG Rui

Date: Wed Apr 29 2026 - 08:09:09 EST


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 <ardb@xxxxxxxxxx>
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..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