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

WANG Rui <[email protected]>
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.

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..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)
+{
+	unsigned long start = 0;
+	unsigned int 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 = 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.