Commit 5b710aa8 authored by WANG Rui's avatar WANG Rui Committed by Huacai Chen
Browse files

LoongArch: Avoid initrd overlap during kernel relocation



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: default avatarArd Biesheuvel <ardb@kernel.org>
Signed-off-by: default avatarWANG Rui <wangrui@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent 08ade00f
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -222,14 +222,52 @@ 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;
	char *p, *endp, *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) == ' ')) {
		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 kernel_start, kernel_size;
	unsigned long initrd_start, 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) {
		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/initramfs overlaps kernel */
	}

	return 1;
}
#endif