All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] efi/arm64: work around Image placement issues
@ 2021-07-26 10:09 ` Ard Biesheuvel
  0 siblings, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2021-07-26 10:09 UTC (permalink / raw)
  To: linux-efi; +Cc: linux-arm-kernel, Ard Biesheuvel, Benjamin Herrenschmidt

Ben reported that distro GRUB may fail to boot in some circumstances,
and tracked it down to an issue in the way distro GRUB allocates space
for the image. Due to an oversight (addressed in patch #2), this
condition is rarely triggered, but let's work around it in any case (#1)

Build tested only.

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Ard Biesheuvel (2):
  efi/libstub: arm64: Force Image reallocation if BSS was not reserved
  efistub: arm64: relax 2M alignment again for relocatable kernels

 drivers/firmware/efi/libstub/arm64-stub.c | 65 +++++++++++++++++---
 1 file changed, 55 insertions(+), 10 deletions(-)

-- 
2.20.1


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

* [PATCH v2 0/2] efi/arm64: work around Image placement issues
@ 2021-07-26 10:09 ` Ard Biesheuvel
  0 siblings, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2021-07-26 10:09 UTC (permalink / raw)
  To: linux-efi; +Cc: linux-arm-kernel, Ard Biesheuvel, Benjamin Herrenschmidt

Ben reported that distro GRUB may fail to boot in some circumstances,
and tracked it down to an issue in the way distro GRUB allocates space
for the image. Due to an oversight (addressed in patch #2), this
condition is rarely triggered, but let's work around it in any case (#1)

Build tested only.

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Ard Biesheuvel (2):
  efi/libstub: arm64: Force Image reallocation if BSS was not reserved
  efistub: arm64: relax 2M alignment again for relocatable kernels

 drivers/firmware/efi/libstub/arm64-stub.c | 65 +++++++++++++++++---
 1 file changed, 55 insertions(+), 10 deletions(-)

-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v2 1/2] efi/libstub: arm64: Force Image reallocation if BSS was not reserved
  2021-07-26 10:09 ` Ard Biesheuvel
@ 2021-07-26 10:09   ` Ard Biesheuvel
  -1 siblings, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2021-07-26 10:09 UTC (permalink / raw)
  To: linux-efi; +Cc: linux-arm-kernel, Ard Biesheuvel

Distro versions of GRUB replace the usual LoadImage/StartImage calls
used to load the kernel image with some local code that fails to honor
the allocation requirements described in the PE/COFF header, as it
does not account for the image's BSS section at all: it fails to
allocate space for it, and fails to zero initialize it.

Since the EFI stub itself is allocated in the .init segment, which is
in the middle of the image, its BSS section is not impacted by this,
and the main consequence of this omission is that the BSS section may
overlap with memory regions that are already used by the firmware.

So let's warn about this condition, and force image reallocation to
occur in this case, which works around the problem.

Fixes: 82046702e288 ("efi/libstub/arm64: Replace 'preferred' offset with alignment check")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/libstub/arm64-stub.c | 49 +++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 7bf0a7acae5e..3698c1ce2940 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -34,6 +34,51 @@ efi_status_t check_platform_features(void)
 	return EFI_SUCCESS;
 }
 
+/*
+ * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
+ * to provide space, and fail to zero it). Check for this condition by double
+ * checking that the first and the last byte of the image are covered by the
+ * same EFI memory map entry.
+ */
+static bool check_image_region(u64 base, u64 size)
+{
+	unsigned long map_size, desc_size, buff_size;
+	efi_memory_desc_t *memory_map;
+	struct efi_boot_memmap map;
+	efi_status_t status;
+	bool ret = false;
+	int map_offset;
+
+	map.map =	&memory_map;
+	map.map_size =	&map_size;
+	map.desc_size =	&desc_size;
+	map.desc_ver =	NULL;
+	map.key_ptr =	NULL;
+	map.buff_size =	&buff_size;
+
+	status = efi_get_memory_map(&map);
+	if (status != EFI_SUCCESS)
+		return false;
+
+	for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+		efi_memory_desc_t *md = (void *)memory_map + map_offset;
+		u64 end = md->phys_addr + md->num_pages * EFI_PAGE_SIZE;
+
+		/*
+		 * Find the region that covers base, and return whether
+		 * it covers base+size bytes.
+		 */
+		if (base >= md->phys_addr && base < end) {
+			ret = (base + size) <= end;
+			break;
+		}
+	}
+
+	efi_bs_call(free_pool, memory_map);
+
+	return ret;
+}
+
 /*
  * Although relocatable kernels can fix up the misalignment with respect to
  * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
@@ -92,7 +137,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	}
 
 	if (status != EFI_SUCCESS) {
-		if (IS_ALIGNED((u64)_text, min_kimg_align())) {
+		if (!check_image_region((u64)_text, kernel_memsize)) {
+			efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
+		} else 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.
-- 
2.20.1


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

* [PATCH v2 1/2] efi/libstub: arm64: Force Image reallocation if BSS was not reserved
@ 2021-07-26 10:09   ` Ard Biesheuvel
  0 siblings, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2021-07-26 10:09 UTC (permalink / raw)
  To: linux-efi; +Cc: linux-arm-kernel, Ard Biesheuvel

Distro versions of GRUB replace the usual LoadImage/StartImage calls
used to load the kernel image with some local code that fails to honor
the allocation requirements described in the PE/COFF header, as it
does not account for the image's BSS section at all: it fails to
allocate space for it, and fails to zero initialize it.

Since the EFI stub itself is allocated in the .init segment, which is
in the middle of the image, its BSS section is not impacted by this,
and the main consequence of this omission is that the BSS section may
overlap with memory regions that are already used by the firmware.

So let's warn about this condition, and force image reallocation to
occur in this case, which works around the problem.

Fixes: 82046702e288 ("efi/libstub/arm64: Replace 'preferred' offset with alignment check")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/libstub/arm64-stub.c | 49 +++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 7bf0a7acae5e..3698c1ce2940 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -34,6 +34,51 @@ efi_status_t check_platform_features(void)
 	return EFI_SUCCESS;
 }
 
+/*
+ * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
+ * to provide space, and fail to zero it). Check for this condition by double
+ * checking that the first and the last byte of the image are covered by the
+ * same EFI memory map entry.
+ */
+static bool check_image_region(u64 base, u64 size)
+{
+	unsigned long map_size, desc_size, buff_size;
+	efi_memory_desc_t *memory_map;
+	struct efi_boot_memmap map;
+	efi_status_t status;
+	bool ret = false;
+	int map_offset;
+
+	map.map =	&memory_map;
+	map.map_size =	&map_size;
+	map.desc_size =	&desc_size;
+	map.desc_ver =	NULL;
+	map.key_ptr =	NULL;
+	map.buff_size =	&buff_size;
+
+	status = efi_get_memory_map(&map);
+	if (status != EFI_SUCCESS)
+		return false;
+
+	for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+		efi_memory_desc_t *md = (void *)memory_map + map_offset;
+		u64 end = md->phys_addr + md->num_pages * EFI_PAGE_SIZE;
+
+		/*
+		 * Find the region that covers base, and return whether
+		 * it covers base+size bytes.
+		 */
+		if (base >= md->phys_addr && base < end) {
+			ret = (base + size) <= end;
+			break;
+		}
+	}
+
+	efi_bs_call(free_pool, memory_map);
+
+	return ret;
+}
+
 /*
  * Although relocatable kernels can fix up the misalignment with respect to
  * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
@@ -92,7 +137,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	}
 
 	if (status != EFI_SUCCESS) {
-		if (IS_ALIGNED((u64)_text, min_kimg_align())) {
+		if (!check_image_region((u64)_text, kernel_memsize)) {
+			efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
+		} else 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.
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

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

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")
Signed-off-by: Ard Biesheuvel <ardb@kernel.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 3698c1ce2940..6f214c9c303e 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -79,18 +79,6 @@ static bool check_image_region(u64 base, u64 size)
 	return ret;
 }
 
-/*
- * 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,
@@ -101,6 +89,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),
@@ -130,7 +128,7 @@ 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;
@@ -139,7 +137,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	if (status != EFI_SUCCESS) {
 		if (!check_image_region((u64)_text, kernel_memsize)) {
 			efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
-		} else if (IS_ALIGNED((u64)_text, min_kimg_align())) {
+		} else 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.
@@ -150,7 +148,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] 9+ messages in thread

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

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")
Signed-off-by: Ard Biesheuvel <ardb@kernel.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 3698c1ce2940..6f214c9c303e 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -79,18 +79,6 @@ static bool check_image_region(u64 base, u64 size)
 	return ret;
 }
 
-/*
- * 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,
@@ -101,6 +89,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),
@@ -130,7 +128,7 @@ 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;
@@ -139,7 +137,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	if (status != EFI_SUCCESS) {
 		if (!check_image_region((u64)_text, kernel_memsize)) {
 			efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
-		} else if (IS_ALIGNED((u64)_text, min_kimg_align())) {
+		} else 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.
@@ -150,7 +148,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


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 1/2] efi/libstub: arm64: Force Image reallocation if BSS was not reserved
  2021-07-26 10:09   ` Ard Biesheuvel
@ 2021-07-26 11:33     ` Benjamin Herrenschmidt
  -1 siblings, 0 replies; 9+ messages in thread
From: Benjamin Herrenschmidt @ 2021-07-26 11:33 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-efi; +Cc: linux-arm-kernel

On Mon, 2021-07-26 at 12:09 +0200, Ard Biesheuvel wrote:
> Distro versions of GRUB replace the usual LoadImage/StartImage calls
> used to load the kernel image with some local code that fails to
> honor the allocation requirements described in the PE/COFF header, as
> it does not account for the image's BSS section at all: it fails to
> allocate space for it, and fails to zero initialize it.
> 
> Since the EFI stub itself is allocated in the .init segment, which is
> in the middle of the image, its BSS section is not impacted by this,
> and the main consequence of this omission is that the BSS section may
> overlap with memory regions that are already used by the firmware.
> 
> So let's warn about this condition, and force image reallocation to
> occur in this case, which works around the problem.

Ah I did miss that... looking at drivers/firmware/efi/libstub/Makefile:

STUBCOPY_FLAGS-$(CONFIG_ARM64)	+= --prefix-alloc-sections=.init \

and arm64's .lds:

	.init.data : {
		INIT_DATA
		INIT_SETUP(16)
		INIT_CALLS
		CON_INITCALL
		INIT_RAM_FS
		*(.init.rodata.* .init.bss)	/* from the EFI stub */
	}

Gosh ... that does indeed save the day in the relocation case. Any
particular reason why we did this though ? This causes the kernel image
to be bigger than it {c,sh}ould ... We already had cases of broken
bootloaders we knew about or just luck ?

Cheers.
Ben.

> Fixes: 82046702e288 ("efi/libstub/arm64: Replace 'preferred' offset
> with alignment check")
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  drivers/firmware/efi/libstub/arm64-stub.c | 49 +++++++++++++++++++-
>  1 file changed, 48 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/efi/libstub/arm64-stub.c
> b/drivers/firmware/efi/libstub/arm64-stub.c
> index 7bf0a7acae5e..3698c1ce2940 100644
> --- a/drivers/firmware/efi/libstub/arm64-stub.c
> +++ b/drivers/firmware/efi/libstub/arm64-stub.c
> @@ -34,6 +34,51 @@ efi_status_t check_platform_features(void)
>  	return EFI_SUCCESS;
>  }
>  
> +/*
> + * Distro versions of GRUB may ignore the BSS allocation entirely
> (i.e., fail
> + * to provide space, and fail to zero it). Check for this condition
> by double
> + * checking that the first and the last byte of the image are
> covered by the
> + * same EFI memory map entry.
> + */
> +static bool check_image_region(u64 base, u64 size)
> +{
> +	unsigned long map_size, desc_size, buff_size;
> +	efi_memory_desc_t *memory_map;
> +	struct efi_boot_memmap map;
> +	efi_status_t status;
> +	bool ret = false;
> +	int map_offset;
> +
> +	map.map =	&memory_map;
> +	map.map_size =	&map_size;
> +	map.desc_size =	&desc_size;
> +	map.desc_ver =	NULL;
> +	map.key_ptr =	NULL;
> +	map.buff_size =	&buff_size;
> +
> +	status = efi_get_memory_map(&map);
> +	if (status != EFI_SUCCESS)
> +		return false;
> +
> +	for (map_offset = 0; map_offset < map_size; map_offset +=
> desc_size) {
> +		efi_memory_desc_t *md = (void *)memory_map +
> map_offset;
> +		u64 end = md->phys_addr + md->num_pages *
> EFI_PAGE_SIZE;
> +
> +		/*
> +		 * Find the region that covers base, and return whether
> +		 * it covers base+size bytes.
> +		 */
> +		if (base >= md->phys_addr && base < end) {
> +			ret = (base + size) <= end;
> +			break;
> +		}
> +	}
> +
> +	efi_bs_call(free_pool, memory_map);
> +
> +	return ret;
> +}
> +
>  /*
>   * Although relocatable kernels can fix up the misalignment with
> respect to
>   * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly
> out of
> @@ -92,7 +137,9 @@ efi_status_t handle_kernel_image(unsigned long
> *image_addr,
>  	}
>  
>  	if (status != EFI_SUCCESS) {
> -		if (IS_ALIGNED((u64)_text, min_kimg_align())) {
> +		if (!check_image_region((u64)_text, kernel_memsize)) {
> +			efi_err("FIRMWARE BUG: Image BSS overlaps
> adjacent EFI memory region\n");
> +		} else 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.


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

* Re: [PATCH v2 1/2] efi/libstub: arm64: Force Image reallocation if BSS was not reserved
@ 2021-07-26 11:33     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 9+ messages in thread
From: Benjamin Herrenschmidt @ 2021-07-26 11:33 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-efi; +Cc: linux-arm-kernel

On Mon, 2021-07-26 at 12:09 +0200, Ard Biesheuvel wrote:
> Distro versions of GRUB replace the usual LoadImage/StartImage calls
> used to load the kernel image with some local code that fails to
> honor the allocation requirements described in the PE/COFF header, as
> it does not account for the image's BSS section at all: it fails to
> allocate space for it, and fails to zero initialize it.
> 
> Since the EFI stub itself is allocated in the .init segment, which is
> in the middle of the image, its BSS section is not impacted by this,
> and the main consequence of this omission is that the BSS section may
> overlap with memory regions that are already used by the firmware.
> 
> So let's warn about this condition, and force image reallocation to
> occur in this case, which works around the problem.

Ah I did miss that... looking at drivers/firmware/efi/libstub/Makefile:

STUBCOPY_FLAGS-$(CONFIG_ARM64)	+= --prefix-alloc-sections=.init \

and arm64's .lds:

	.init.data : {
		INIT_DATA
		INIT_SETUP(16)
		INIT_CALLS
		CON_INITCALL
		INIT_RAM_FS
		*(.init.rodata.* .init.bss)	/* from the EFI stub */
	}

Gosh ... that does indeed save the day in the relocation case. Any
particular reason why we did this though ? This causes the kernel image
to be bigger than it {c,sh}ould ... We already had cases of broken
bootloaders we knew about or just luck ?

Cheers.
Ben.

> Fixes: 82046702e288 ("efi/libstub/arm64: Replace 'preferred' offset
> with alignment check")
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  drivers/firmware/efi/libstub/arm64-stub.c | 49 +++++++++++++++++++-
>  1 file changed, 48 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/efi/libstub/arm64-stub.c
> b/drivers/firmware/efi/libstub/arm64-stub.c
> index 7bf0a7acae5e..3698c1ce2940 100644
> --- a/drivers/firmware/efi/libstub/arm64-stub.c
> +++ b/drivers/firmware/efi/libstub/arm64-stub.c
> @@ -34,6 +34,51 @@ efi_status_t check_platform_features(void)
>  	return EFI_SUCCESS;
>  }
>  
> +/*
> + * Distro versions of GRUB may ignore the BSS allocation entirely
> (i.e., fail
> + * to provide space, and fail to zero it). Check for this condition
> by double
> + * checking that the first and the last byte of the image are
> covered by the
> + * same EFI memory map entry.
> + */
> +static bool check_image_region(u64 base, u64 size)
> +{
> +	unsigned long map_size, desc_size, buff_size;
> +	efi_memory_desc_t *memory_map;
> +	struct efi_boot_memmap map;
> +	efi_status_t status;
> +	bool ret = false;
> +	int map_offset;
> +
> +	map.map =	&memory_map;
> +	map.map_size =	&map_size;
> +	map.desc_size =	&desc_size;
> +	map.desc_ver =	NULL;
> +	map.key_ptr =	NULL;
> +	map.buff_size =	&buff_size;
> +
> +	status = efi_get_memory_map(&map);
> +	if (status != EFI_SUCCESS)
> +		return false;
> +
> +	for (map_offset = 0; map_offset < map_size; map_offset +=
> desc_size) {
> +		efi_memory_desc_t *md = (void *)memory_map +
> map_offset;
> +		u64 end = md->phys_addr + md->num_pages *
> EFI_PAGE_SIZE;
> +
> +		/*
> +		 * Find the region that covers base, and return whether
> +		 * it covers base+size bytes.
> +		 */
> +		if (base >= md->phys_addr && base < end) {
> +			ret = (base + size) <= end;
> +			break;
> +		}
> +	}
> +
> +	efi_bs_call(free_pool, memory_map);
> +
> +	return ret;
> +}
> +
>  /*
>   * Although relocatable kernels can fix up the misalignment with
> respect to
>   * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly
> out of
> @@ -92,7 +137,9 @@ efi_status_t handle_kernel_image(unsigned long
> *image_addr,
>  	}
>  
>  	if (status != EFI_SUCCESS) {
> -		if (IS_ALIGNED((u64)_text, min_kimg_align())) {
> +		if (!check_image_region((u64)_text, kernel_memsize)) {
> +			efi_err("FIRMWARE BUG: Image BSS overlaps
> adjacent EFI memory region\n");
> +		} else 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.


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 1/2] efi/libstub: arm64: Force Image reallocation if BSS was not reserved
  2021-07-26 10:09   ` Ard Biesheuvel
  (?)
  (?)
@ 2021-07-26 11:38   ` Herrenschmidt, Benjamin
  -1 siblings, 0 replies; 9+ messages in thread
From: Herrenschmidt, Benjamin @ 2021-07-26 11:38 UTC (permalink / raw)
  To: linux-efi, ardb

Looks good but I'll try to actually test it on my repro-setup tomorrow.

Cheers,
Ben.

> On Mon, 2021-07-26 at 12:09 +0200, Ard Biesheuvel wrote:
> Distro versions of GRUB replace the usual LoadImage/StartImage calls
> used to load the kernel image with some local code that fails to
> honor
> the allocation requirements described in the PE/COFF header, as it
> does not account for the image's BSS section at all: it fails to
> allocate space for it, and fails to zero initialize it.
> 
> Since the EFI stub itself is allocated in the .init segment, which is
> in the middle of the image, its BSS section is not impacted by this,
> and the main consequence of this omission is that the BSS section may
> overlap with memory regions that are already used by the firmware.
> 
> So let's warn about this condition, and force image reallocation to
> occur in this case, which works around the problem.
> 
> Fixes: 82046702e288 ("efi/libstub/arm64: Replace 'preferred' offset
> with alignment check")
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  drivers/firmware/efi/libstub/arm64-stub.c | 49 +++++++++++++++++++-
>  1 file changed, 48 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/efi/libstub/arm64-stub.c
> b/drivers/firmware/efi/libstub/arm64-stub.c
> index 7bf0a7acae5e..3698c1ce2940 100644
> --- a/drivers/firmware/efi/libstub/arm64-stub.c
> +++ b/drivers/firmware/efi/libstub/arm64-stub.c
> @@ -34,6 +34,51 @@ efi_status_t check_platform_features(void)
>  	return EFI_SUCCESS;
>  }
>  
> +/*
> + * Distro versions of GRUB may ignore the BSS allocation entirely
> (i.e., fail
> + * to provide space, and fail to zero it). Check for this condition
> by double
> + * checking that the first and the last byte of the image are
> covered by the
> + * same EFI memory map entry.
> + */
> +static bool check_image_region(u64 base, u64 size)
> +{
> +	unsigned long map_size, desc_size, buff_size;
> +	efi_memory_desc_t *memory_map;
> +	struct efi_boot_memmap map;
> +	efi_status_t status;
> +	bool ret = false;
> +	int map_offset;
> +
> +	map.map =	&memory_map;
> +	map.map_size =	&map_size;
> +	map.desc_size =	&desc_size;
> +	map.desc_ver =	NULL;
> +	map.key_ptr =	NULL;
> +	map.buff_size =	&buff_size;
> +
> +	status = efi_get_memory_map(&map);
> +	if (status != EFI_SUCCESS)
> +		return false;
> +
> +	for (map_offset = 0; map_offset < map_size; map_offset +=
> desc_size) {
> +		efi_memory_desc_t *md = (void *)memory_map +
> map_offset;
> +		u64 end = md->phys_addr + md->num_pages *
> EFI_PAGE_SIZE;
> +
> +		/*
> +		 * Find the region that covers base, and return whether
> +		 * it covers base+size bytes.
> +		 */
> +		if (base >= md->phys_addr && base < end) {
> +			ret = (base + size) <= end;
> +			break;
> +		}
> +	}
> +
> +	efi_bs_call(free_pool, memory_map);
> +
> +	return ret;
> +}
> +
>  /*
>   * Although relocatable kernels can fix up the misalignment with
> respect to
>   * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly
> out of
> @@ -92,7 +137,9 @@ efi_status_t handle_kernel_image(unsigned long
> *image_addr,
>  	}
>  
>  	if (status != EFI_SUCCESS) {
> -		if (IS_ALIGNED((u64)_text, min_kimg_align())) {
> +		if (!check_image_region((u64)_text, kernel_memsize)) {
> +			efi_err("FIRMWARE BUG: Image BSS overlaps
> adjacent EFI memory region\n");
> +		} else 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.

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

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

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-26 10:09 [PATCH v2 0/2] efi/arm64: work around Image placement issues Ard Biesheuvel
2021-07-26 10:09 ` Ard Biesheuvel
2021-07-26 10:09 ` [PATCH v2 1/2] efi/libstub: arm64: Force Image reallocation if BSS was not reserved Ard Biesheuvel
2021-07-26 10:09   ` Ard Biesheuvel
2021-07-26 11:33   ` Benjamin Herrenschmidt
2021-07-26 11:33     ` Benjamin Herrenschmidt
2021-07-26 11:38   ` Herrenschmidt, Benjamin
2021-07-26 10:09 ` [PATCH v2 2/2] efistub: arm64: relax 2M alignment again for relocatable kernels Ard Biesheuvel
2021-07-26 10:09   ` Ard Biesheuvel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.