linux-efi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] efistub: arm64: relax 2M alignment again for relocatable kernels
@ 2021-07-22 10:26 Ard Biesheuvel
  2021-07-26  4:09 ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 2+ messages in thread
From: Ard Biesheuvel @ 2021-07-22 10:26 UTC (permalink / raw)
  To: linux-efi; +Cc: linux-arm-kernel, Ard Biesheuvel, Benjamin Herrenschmidt

Commit 82046702e288 ("efi/libstub/arm64: Replace 'preferred' offset with
alignment check") simplified the way the stub moves the kernel image
around in memory before booting it, given that a relocatable image does
not need to be copied to a 2M aligned offset if it was loaded on a 64k
boundary by EFI.

Commit d32de9130f6c ("efi/arm64: libstub: Deal gracefully with
EFI_RNG_PROTOCOL failure") inadvertently defeated this logic by
overriding the value of efi_nokaslr if EFI_RNG_PROTOCOL is not
available, which was mistaked by the loader logic as an explicit request
on the part of the user to disable KASLR and any associated relocation
of an Image not loaded on a 2M boundary.

So let's reinstate this functionality, by capturing the value of
efi_nokaslr at function entry to choose the minimum alignment.

Fixes: d32de9130f6c ("efi/arm64: libstub: Deal gracefully with EFI_RNG_PROTOCOL failure")
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
This fixes the regression that was discussed in [0], but given that it
is very likely to break Ben's use case again, I'll sit on it for the
time being.

[0] https://lore.kernel.org/linux-efi/161920fc31ec4168290ca31b3e4ac7a75ac1df6b.camel@kernel.crashing.org/

 drivers/firmware/efi/libstub/arm64-stub.c | 28 +++++++++-----------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 7bf0a7acae5e..98e013404ca3 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -34,18 +34,6 @@ efi_status_t check_platform_features(void)
 	return EFI_SUCCESS;
 }
 
-/*
- * Although relocatable kernels can fix up the misalignment with respect to
- * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
- * sync with those recorded in the vmlinux when kaslr is disabled but the
- * image required relocation anyway. Therefore retain 2M alignment unless
- * KASLR is in use.
- */
-static u64 min_kimg_align(void)
-{
-	return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
-}
-
 efi_status_t handle_kernel_image(unsigned long *image_addr,
 				 unsigned long *image_size,
 				 unsigned long *reserve_addr,
@@ -56,6 +44,16 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	unsigned long kernel_size, kernel_memsize = 0;
 	u32 phys_seed = 0;
 
+	/*
+	 * Although relocatable kernels can fix up the misalignment with
+	 * respect to MIN_KIMG_ALIGN, the resulting virtual text addresses are
+	 * subtly out of sync with those recorded in the vmlinux when kaslr is
+	 * disabled but the image required relocation anyway. Therefore retain
+	 * 2M alignment if KASLR was explicitly disabled, even if it was not
+	 * going to be activated to begin with.
+	 */
+	u64 min_kimg_align = efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
+
 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
 		if (!efi_nokaslr) {
 			status = efi_get_random_bytes(sizeof(phys_seed),
@@ -85,14 +83,14 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 		 * If KASLR is enabled, and we have some randomness available,
 		 * locate the kernel at a randomized offset in physical memory.
 		 */
-		status = efi_random_alloc(*reserve_size, min_kimg_align(),
+		status = efi_random_alloc(*reserve_size, min_kimg_align,
 					  reserve_addr, phys_seed);
 	} else {
 		status = EFI_OUT_OF_RESOURCES;
 	}
 
 	if (status != EFI_SUCCESS) {
-		if (IS_ALIGNED((u64)_text, min_kimg_align())) {
+		if (IS_ALIGNED((u64)_text, min_kimg_align)) {
 			/*
 			 * Just execute from wherever we were loaded by the
 			 * UEFI PE/COFF loader if the alignment is suitable.
@@ -103,7 +101,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 		}
 
 		status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
-						    ULONG_MAX, min_kimg_align());
+						    ULONG_MAX, min_kimg_align);
 
 		if (status != EFI_SUCCESS) {
 			efi_err("Failed to relocate kernel\n");
-- 
2.20.1


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

* Re: [PATCH] efistub: arm64: relax 2M alignment again for relocatable kernels
  2021-07-22 10:26 [PATCH] efistub: arm64: relax 2M alignment again for relocatable kernels Ard Biesheuvel
@ 2021-07-26  4:09 ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 2+ messages in thread
From: Benjamin Herrenschmidt @ 2021-07-26  4:09 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-efi; +Cc: linux-arm-kernel

On Thu, 2021-07-22 at 12:26 +0200, Ard Biesheuvel wrote:
> Commit 82046702e288 ("efi/libstub/arm64: Replace 'preferred' offset with
> alignment check") simplified the way the stub moves the kernel image
> around in memory before booting it, given that a relocatable image does
> not need to be copied to a 2M aligned offset if it was loaded on a 64k
> boundary by EFI.
> 
> Commit d32de9130f6c ("efi/arm64: libstub: Deal gracefully with
> EFI_RNG_PROTOCOL failure") inadvertently defeated this logic by
> overriding the value of efi_nokaslr if EFI_RNG_PROTOCOL is not
> available, which was mistaked by the loader logic as an explicit request
> on the part of the user to disable KASLR and any associated relocation
> of an Image not loaded on a 2M boundary.
> 
> So let's reinstate this functionality, by capturing the value of
> efi_nokaslr at function entry to choose the minimum alignment.
> 
> Fixes: d32de9130f6c ("efi/arm64: libstub: Deal gracefully with EFI_RNG_PROTOCOL failure")
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> This fixes the regression that was discussed in [0], but given that it
> is very likely to break Ben's use case again, I'll sit on it for the
> time being.

The bug is in the version of grub carried by some distros actually. The
stricter alignment forces the stub to reallocate the image in ways that
manages to generally avoid it (but it's all luck). Long story short:
those grubs don't allocate room for the kernel bss (and don't zero it),
thus there's a chance for it to overlap other pre-boot allocations such
as EFI runtime services, the initrd, fdt, whatever else...

So the kernel will break more often with this patch until grub is fixed
in those distros (working on it ...).

Note: If you work on a distro and you carry the grub2 patch that takes
out LoadImage/StartImage from grub-core/loader/arm64/linux.c in favor
of the shim lock protocol, poke me, I have a patch for you :)

Cheers,
Ben.



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

end of thread, other threads:[~2021-07-26  4:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-22 10:26 [PATCH] efistub: arm64: relax 2M alignment again for relocatable kernels Ard Biesheuvel
2021-07-26  4:09 ` Benjamin Herrenschmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).