public inbox for linux-efi@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] LoongArch: Move KASLR to EFI stub to avoid initrd overlap
@ 2026-04-26 12:02 WANG Rui
  2026-04-26 12:02 ` [RFC PATCH 1/3] LoongArch: Allow rdtime_h and rdtime_l in 64-bit builds WANG Rui
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: WANG Rui @ 2026-04-26 12:02 UTC (permalink / raw)
  To: Huacai Chen, Ard Biesheuvel
  Cc: WANG Xuerui, Ilias Apalodimas, loongarch, linux-efi, linux-kernel,
	WANG Rui

This series addresses a potential overlap issue between the kernel
image and the initrd when KASLR is enabled.

In the normal boot flow, the bootloader is responsible for loading
both vmlinux and the initrd, and it can guarantee that the two do
not overlap in memory. However, this assumption only holds as long
as neither image changes its location afterwards.

The in-kernel KASLR implementation breaks that assumption. When the
initrd is placed close to the kernel image, randomizing the kernel
location at runtime may move it into the initrd region, leading to
memory corruption early during boot.

To fix this, this series moves the KASLR logic out of the kernel
proper and into the EFI stub. With this change, the final placement
of both the kernel image and the initrd is determined by the EFI
memory allocator. This ensures that the two allocations are
coordinated and cannot overlap.

Functionally, the kernel still supports KASLR as before, but the
randomization now happens before the kernel is entered, rather than
during early kernel relocation.

WANG Rui (3):
  LoongArch: Allow rdtime_h and rdtime_l in 64-bit builds
  efi/loongarch: Randomize kernel preferred address for KASLR
  LoongArch: Remove KASLR handling from relocate_kernel()

 arch/loongarch/include/asm/efi.h         |   4 +-
 arch/loongarch/include/asm/loongarch.h   |   6 -
 arch/loongarch/include/asm/setup.h       |   2 +-
 arch/loongarch/kernel/head.S             |  12 --
 arch/loongarch/kernel/relocate.c         | 182 +----------------------
 drivers/firmware/efi/libstub/loongarch.c |  15 ++
 6 files changed, 24 insertions(+), 197 deletions(-)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC PATCH 1/3] LoongArch: Allow rdtime_h and rdtime_l in 64-bit builds
  2026-04-26 12:02 [RFC PATCH 0/3] LoongArch: Move KASLR to EFI stub to avoid initrd overlap WANG Rui
@ 2026-04-26 12:02 ` WANG Rui
  2026-04-26 12:02 ` [RFC PATCH 2/3] efi/loongarch: Randomize kernel preferred address for KASLR WANG Rui
  2026-04-26 12:02 ` [RFC PATCH 3/3] LoongArch: Remove KASLR handling from relocate_kernel WANG Rui
  2 siblings, 0 replies; 6+ messages in thread
From: WANG Rui @ 2026-04-26 12:02 UTC (permalink / raw)
  To: Huacai Chen, Ard Biesheuvel
  Cc: WANG Xuerui, Ilias Apalodimas, loongarch, linux-efi, linux-kernel,
	WANG Rui

Remove the CONFIG_32BIT guard around rdtime_h() and rdtime_l()
so they can also be used in 64-bit builds.

Signed-off-by: WANG Rui <r@hev.cc>
---
 arch/loongarch/include/asm/loongarch.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
index 2a6bc99177d8..bb2da9c58411 100644
--- a/arch/loongarch/include/asm/loongarch.h
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -1248,8 +1248,6 @@
 
 #ifndef __ASSEMBLER__
 
-#ifdef CONFIG_32BIT
-
 static __always_inline u32 rdtime_h(void)
 {
 	u32 val = 0;
@@ -1274,8 +1272,6 @@ static __always_inline u32 rdtime_l(void)
 	return val;
 }
 
-#else
-
 static __always_inline u64 rdtime_d(void)
 {
 	u64 val = 0;
@@ -1288,8 +1284,6 @@ static __always_inline u64 rdtime_d(void)
 	return val;
 }
 
-#endif
-
 static inline unsigned int get_csr_cpuid(void)
 {
 	return csr_read32(LOONGARCH_CSR_CPUID);
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC PATCH 2/3] efi/loongarch: Randomize kernel preferred address for KASLR
  2026-04-26 12:02 [RFC PATCH 0/3] LoongArch: Move KASLR to EFI stub to avoid initrd overlap WANG Rui
  2026-04-26 12:02 ` [RFC PATCH 1/3] LoongArch: Allow rdtime_h and rdtime_l in 64-bit builds WANG Rui
@ 2026-04-26 12:02 ` WANG Rui
  2026-04-27  5:07   ` Lisa Robinson
  2026-04-26 12:02 ` [RFC PATCH 3/3] LoongArch: Remove KASLR handling from relocate_kernel WANG Rui
  2 siblings, 1 reply; 6+ messages in thread
From: WANG Rui @ 2026-04-26 12:02 UTC (permalink / raw)
  To: Huacai Chen, Ard Biesheuvel
  Cc: WANG Xuerui, Ilias Apalodimas, loongarch, linux-efi, linux-kernel,
	WANG Rui

Introduce efi_get_kimg_kaslr_address() to compute the preferred
kernel image address dynamically when CONFIG_RANDOMIZE_BASE is
enabled. The function derives a random offset using EFI-provided
randomness combined with the timer value, and constrains it within
CONFIG_RANDOMIZE_BASE_MAX_OFFSET.

Update EFI_KIMG_PREFERRED_ADDRESS to call this helper so that the
EFI stub can select a randomized load address when KASLR is active,
while preserving the original base address behavior when KASLR is
disabled or nokaslr is specified.

Signed-off-by: WANG Rui <r@hev.cc>
---
 arch/loongarch/include/asm/efi.h         |  4 +++-
 drivers/firmware/efi/libstub/loongarch.c | 15 +++++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h
index eddc8e79b3fa..f831320efd41 100644
--- a/arch/loongarch/include/asm/efi.h
+++ b/arch/loongarch/include/asm/efi.h
@@ -30,6 +30,8 @@ static inline unsigned long efi_get_kimg_min_align(void)
 	return SZ_2M;
 }
 
-#define EFI_KIMG_PREFERRED_ADDRESS	PHYSADDR(VMLINUX_LOAD_ADDRESS)
+unsigned long efi_get_kimg_kaslr_address(void);
+
+#define EFI_KIMG_PREFERRED_ADDRESS	efi_get_kimg_kaslr_address()
 
 #endif /* _ASM_LOONGARCH_EFI_H */
diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c
index 9825f5218137..80ba7d69e1b3 100644
--- a/drivers/firmware/efi/libstub/loongarch.c
+++ b/drivers/firmware/efi/libstub/loongarch.c
@@ -38,6 +38,21 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
 	return EFI_SUCCESS;
 }
 
+unsigned long efi_get_kimg_kaslr_address(void)
+{
+	unsigned int random_offset = 0;
+
+#ifdef CONFIG_RANDOMIZE_BASE
+	if (!efi_nokaslr) {
+		efi_get_random_bytes(sizeof(random_offset), (u8 *)&random_offset);
+		random_offset ^= (rdtime_l() << 16);
+		random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
+	}
+#endif
+
+	return PHYSADDR(VMLINUX_LOAD_ADDRESS) + random_offset;
+}
+
 unsigned long __weak kernel_entry_address(unsigned long kernel_addr,
 		efi_loaded_image_t *image)
 {
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC PATCH 3/3] LoongArch: Remove KASLR handling from relocate_kernel
  2026-04-26 12:02 [RFC PATCH 0/3] LoongArch: Move KASLR to EFI stub to avoid initrd overlap WANG Rui
  2026-04-26 12:02 ` [RFC PATCH 1/3] LoongArch: Allow rdtime_h and rdtime_l in 64-bit builds WANG Rui
  2026-04-26 12:02 ` [RFC PATCH 2/3] efi/loongarch: Randomize kernel preferred address for KASLR WANG Rui
@ 2026-04-26 12:02 ` WANG Rui
  2 siblings, 0 replies; 6+ messages in thread
From: WANG Rui @ 2026-04-26 12:02 UTC (permalink / raw)
  To: Huacai Chen, Ard Biesheuvel
  Cc: WANG Xuerui, Ilias Apalodimas, loongarch, linux-efi, linux-kernel,
	WANG Rui

With KASLR address selection handled earlier in the boot flow, the
in-kernel relocation logic is no longer needed.

Remove the code that determines a randomized relocation address and
copies the kernel image at runtime. relocate_kernel() is simplified
to apply relocation fixups only, and its return type is updated to
void since no offset is returned anymore.

Signed-off-by: WANG Rui <r@hev.cc>
---
 arch/loongarch/include/asm/setup.h |   2 +-
 arch/loongarch/kernel/head.S       |  12 --
 arch/loongarch/kernel/relocate.c   | 182 +----------------------------
 3 files changed, 6 insertions(+), 190 deletions(-)

diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h
index f81375e5e89c..7e427484834d 100644
--- a/arch/loongarch/include/asm/setup.h
+++ b/arch/loongarch/include/asm/setup.h
@@ -42,7 +42,7 @@ extern long __relr_dyn_begin;
 extern long __relr_dyn_end;
 #endif
 
-extern unsigned long __init relocate_kernel(void);
+extern void __init relocate_kernel(void);
 
 #endif
 
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index 4eed7bc312a8..e134f8b084a9 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -84,18 +84,6 @@ SYM_CODE_START(kernel_entry)			# kernel entry point
 
 	bl		relocate_kernel
 
-#ifdef CONFIG_RANDOMIZE_BASE
-	/* Repoint the sp into the new kernel */
-	PTR_LI		sp, (_THREAD_SIZE - PT_SIZE)
-	PTR_ADD		sp, sp, tp
-	set_saved_sp	sp, t0, t1
-
-	/* Jump to the new kernel: new_pc = current_pc + random_offset */
-	pcaddi		t0, 0
-	PTR_ADD		t0, t0, a0
-	jirl		zero, t0, 0xc
-#endif /* CONFIG_RANDOMIZE_BASE */
-
 #endif /* CONFIG_RELOCATABLE */
 
 #ifdef CONFIG_KASAN
diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
index 16f6a9b39659..a9273c80a9bf 100644
--- a/arch/loongarch/kernel/relocate.c
+++ b/arch/loongarch/kernel/relocate.c
@@ -18,7 +18,6 @@
 #include <asm/setup.h>
 
 #define RELOCATED(x) ((void *)((long)x + reloc_offset))
-#define RELOCATED_KASLR(x) ((void *)((long)x + random_offset))
 
 static unsigned long reloc_offset;
 
@@ -58,13 +57,13 @@ static inline void __init relocate_relative(void)
 #endif
 }
 
-static inline void __init relocate_absolute(long random_offset)
+static inline void __init relocate_absolute(void)
 {
 	void *begin, *end;
 	struct rela_la_abs *p;
 
-	begin = RELOCATED_KASLR(&__la_abs_begin);
-	end   = RELOCATED_KASLR(&__la_abs_end);
+	begin = &__la_abs_begin;
+	end   = &__la_abs_end;
 
 	for (p = begin; (void *)p < end; p++) {
 		long v = p->symvalue;
@@ -90,190 +89,19 @@ static inline void __init relocate_absolute(long random_offset)
 	}
 }
 
-#ifdef CONFIG_RANDOMIZE_BASE
-static inline __init unsigned long rotate_xor(unsigned long hash,
-					      const void *area, size_t size)
+void __init relocate_kernel(void)
 {
-	size_t i, diff;
-	const typeof(hash) *ptr = PTR_ALIGN(area, sizeof(hash));
-
-	diff = (void *)ptr - area;
-	if (size < diff + sizeof(hash))
-		return hash;
-
-	size = ALIGN_DOWN(size - diff, sizeof(hash));
-
-	for (i = 0; i < size / sizeof(hash); i++) {
-		/* Rotate by odd number of bits and XOR. */
-		hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
-		hash ^= ptr[i];
-	}
-
-	return hash;
-}
-
-static inline __init unsigned long get_random_boot(void)
-{
-	unsigned long hash = 0;
-	unsigned long entropy = random_get_entropy();
-
-	/* Attempt to create a simple but unpredictable starting entropy. */
-	hash = rotate_xor(hash, linux_banner, strlen(linux_banner));
-
-	/* Add in any runtime entropy we can get */
-	hash = rotate_xor(hash, &entropy, sizeof(entropy));
-
-	return hash;
-}
-
-static int __init nokaslr(char *p)
-{
-	return 0; /* Just silence the boot warning */
-}
-early_param("nokaslr", nokaslr);
-
-#define KASLR_DISABLED_MESSAGE "KASLR is disabled by %s in %s cmdline.\n"
-
-static inline __init bool kaslr_disabled(void)
-{
-	char *str;
-	const char *builtin_cmdline = CONFIG_CMDLINE;
-
-	str = strstr(builtin_cmdline, "nokaslr");
-	if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) {
-		pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "built-in");
-		return true;
-	}
-
-	str = strstr(boot_command_line, "nokaslr");
-	if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) {
-		pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "bootloader");
-		return true;
-	}
-
-#ifdef CONFIG_HIBERNATION
-	str = strstr(builtin_cmdline, "nohibernate");
-	if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
-		return false;
-
-	str = strstr(boot_command_line, "nohibernate");
-	if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
-		return false;
-
-	str = strstr(builtin_cmdline, "noresume");
-	if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
-		return false;
-
-	str = strstr(boot_command_line, "noresume");
-	if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
-		return false;
-
-	str = strstr(builtin_cmdline, "resume=");
-	if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) {
-		pr_info(KASLR_DISABLED_MESSAGE, "\'resume=\'", "built-in");
-		return true;
-	}
-
-	str = strstr(boot_command_line, "resume=");
-	if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) {
-		pr_info(KASLR_DISABLED_MESSAGE, "\'resume=\'", "bootloader");
-		return true;
-	}
-#endif
-
-	str = strstr(boot_command_line, "kexec_file");
-	if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) {
-		pr_info(KASLR_DISABLED_MESSAGE, "\'kexec_file\'", "bootloader");
-		return true;
-	}
-
-	return false;
-}
-
-/* Choose a new address for the kernel */
-static inline void __init *determine_relocation_address(void)
-{
-	unsigned long kernel_length;
-	unsigned long random_offset;
-	void *destination = _text;
-
-	if (kaslr_disabled())
-		return destination;
-
-	kernel_length = (unsigned long)_end - (unsigned long)_text;
-
-	random_offset = get_random_boot() << 16;
-	random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
-	if (random_offset < kernel_length)
-		random_offset += ALIGN(kernel_length, 0xffff);
-
-	return RELOCATED_KASLR(destination);
-}
-
-static inline int __init relocation_addr_valid(void *location_new)
-{
-	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 */
-
-	return 1;
-}
-#endif
-
-static inline void __init update_reloc_offset(unsigned long *addr, long random_offset)
-{
-	unsigned long *new_addr = (unsigned long *)RELOCATED_KASLR(addr);
-
-	*new_addr = (unsigned long)reloc_offset;
-}
-
-unsigned long __init relocate_kernel(void)
-{
-	unsigned long kernel_length;
-	unsigned long random_offset = 0;
-	void *location_new = _text; /* Default to original kernel start */
 	char *cmdline = early_memremap_ro(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */
 
 	strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);
 
-#ifdef CONFIG_RANDOMIZE_BASE
-	location_new = determine_relocation_address();
-
-	/* Sanity check relocation address */
-	if (relocation_addr_valid(location_new))
-		random_offset = (unsigned long)location_new - (unsigned long)(_text);
-#endif
 	reloc_offset = (unsigned long)_text - VMLINUX_LOAD_ADDRESS;
 	early_memunmap(cmdline, COMMAND_LINE_SIZE);
 
-	if (random_offset) {
-		kernel_length = (unsigned long)(_end) - (unsigned long)(_text);
-
-		/* Copy the kernel to it's new location */
-		memcpy(location_new, _text, kernel_length);
-
-		/* Sync the caches ready for execution of new kernel */
-		__asm__ __volatile__ (
-			"ibar 0 \t\n"
-			"dbar 0 \t\n"
-			::: "memory");
-
-		reloc_offset += random_offset;
-
-		/* The current thread is now within the relocated kernel */
-		__current_thread_info = RELOCATED_KASLR(__current_thread_info);
-
-		update_reloc_offset(&reloc_offset, random_offset);
-	}
-
 	if (reloc_offset)
 		relocate_relative();
 
-	relocate_absolute(random_offset);
-
-	return random_offset;
+	relocate_absolute();
 }
 
 /*
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH 2/3] efi/loongarch: Randomize kernel preferred address for KASLR
  2026-04-26 12:02 ` [RFC PATCH 2/3] efi/loongarch: Randomize kernel preferred address for KASLR WANG Rui
@ 2026-04-27  5:07   ` Lisa Robinson
  2026-04-27  7:49     ` hev
  0 siblings, 1 reply; 6+ messages in thread
From: Lisa Robinson @ 2026-04-27  5:07 UTC (permalink / raw)
  To: r
  Cc: ardb, chenhuacai, ilias.apalodimas, kernel, linux-efi,
	linux-kernel, loongarch, Lisa Robinson

Hi Rui

> diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c
> index 9825f5218137..80ba7d69e1b3 100644
> --- a/drivers/firmware/efi/libstub/loongarch.c
> +++ b/drivers/firmware/efi/libstub/loongarch.c
> @@ -38,6 +38,21 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
>  	return EFI_SUCCESS;
>  }
>  
> +unsigned long efi_get_kimg_kaslr_address(void)
> +{
> +	unsigned int random_offset = 0;
> +
> +#ifdef CONFIG_RANDOMIZE_BASE
> +	if (!efi_nokaslr) {
> +		efi_get_random_bytes(sizeof(random_offset), (u8 *)&random_offset);
> +		random_offset ^= (rdtime_l() << 16);

random_offset &= ~(efi_get_kimg_min_align() - 1);

> +		random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
> +	}
> +#endif
> +
> +	return PHYSADDR(VMLINUX_LOAD_ADDRESS) + random_offset;
> +}
> +
>  unsigned long __weak kernel_entry_address(unsigned long kernel_addr,
>  		efi_loaded_image_t *image)
>  {

--
Lisa

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH 2/3] efi/loongarch: Randomize kernel preferred address for KASLR
  2026-04-27  5:07   ` Lisa Robinson
@ 2026-04-27  7:49     ` hev
  0 siblings, 0 replies; 6+ messages in thread
From: hev @ 2026-04-27  7:49 UTC (permalink / raw)
  To: Lisa Robinson
  Cc: ardb, chenhuacai, ilias.apalodimas, kernel, linux-efi,
	linux-kernel, loongarch

Hi Lisa,

On Mon, Apr 27, 2026 at 1:08 PM Lisa Robinson <lisa@bytefly.space> wrote:
>
> Hi Rui
>
> > diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c
> > index 9825f5218137..80ba7d69e1b3 100644
> > --- a/drivers/firmware/efi/libstub/loongarch.c
> > +++ b/drivers/firmware/efi/libstub/loongarch.c
> > @@ -38,6 +38,21 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
> >       return EFI_SUCCESS;
> >  }
> >
> > +unsigned long efi_get_kimg_kaslr_address(void)
> > +{
> > +     unsigned int random_offset = 0;
> > +
> > +#ifdef CONFIG_RANDOMIZE_BASE
> > +     if (!efi_nokaslr) {
> > +             efi_get_random_bytes(sizeof(random_offset), (u8 *)&random_offset);
> > +             random_offset ^= (rdtime_l() << 16);
>
> random_offset &= ~(efi_get_kimg_min_align() - 1);

Thanks for pointing that out.

Aligning to 64K here seems preferable. Otherwise, it reduces the entropy.

Thanks,
Rui


>
> > +             random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
> > +     }
> > +#endif
> > +
> > +     return PHYSADDR(VMLINUX_LOAD_ADDRESS) + random_offset;
> > +}
> > +
> >  unsigned long __weak kernel_entry_address(unsigned long kernel_addr,
> >               efi_loaded_image_t *image)
> >  {
>
> --
> Lisa

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-04-27  7:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-26 12:02 [RFC PATCH 0/3] LoongArch: Move KASLR to EFI stub to avoid initrd overlap WANG Rui
2026-04-26 12:02 ` [RFC PATCH 1/3] LoongArch: Allow rdtime_h and rdtime_l in 64-bit builds WANG Rui
2026-04-26 12:02 ` [RFC PATCH 2/3] efi/loongarch: Randomize kernel preferred address for KASLR WANG Rui
2026-04-27  5:07   ` Lisa Robinson
2026-04-27  7:49     ` hev
2026-04-26 12:02 ` [RFC PATCH 3/3] LoongArch: Remove KASLR handling from relocate_kernel WANG Rui

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox