[PATCH 6.1 109/215] efi: libstub: use EFI_LOADER_CODE region when moving the kernel in memory

Greg Kroah-Hartman
2024-03-04T21:46:58Z

From: Ard Biesheuvel <ardb@kernel.org>

commit 9cf42bca30e98a1c6c9e8abf876940a551eaa3d1 upstream.

The EFI spec is not very clear about which permissions are being given
when allocating pages of a certain type. However, it is quite obvious
that EFI_LOADER_CODE is more likely to permit execution than
EFI_LOADER_DATA, which becomes relevant once we permit booting the
kernel proper with the firmware's 1:1 mapping still active.

Ostensibly, recent systems such as the Surface Pro X grant executable
permissions to EFI_LOADER_CODE regions but not EFI_LOADER_DATA regions.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/firmware/efi/libstub/alignedmem.c | 5 +++--
drivers/firmware/efi/libstub/arm64-stub.c | 6 ++++--
drivers/firmware/efi/libstub/efistub.h | 6 ++++--
drivers/firmware/efi/libstub/mem.c | 3 ++-
drivers/firmware/efi/libstub/randomalloc.c | 5 +++--
5 files changed, 16 insertions(+), 9 deletions(-)

--- a/drivers/firmware/efi/libstub/alignedmem.c
+++ b/drivers/firmware/efi/libstub/alignedmem.c
@@ -22,7 +22,8 @@
* Return: status code
*/
efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
- unsigned long max, unsigned long align)
+ unsigned long max, unsigned long align,
+ int memory_type)
{
efi_physical_addr_t alloc_addr;
efi_status_t status;
@@ -36,7 +37,7 @@ efi_status_t efi_allocate_pages_aligned(
slack = align / EFI_PAGE_SIZE - 1;

status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
- EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack,
+ memory_type, size / EFI_PAGE_SIZE + slack,
&alloc_addr);
if (status != EFI_SUCCESS)
return status;
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -180,7 +180,8 @@ efi_status_t handle_kernel_image(unsigne
* locate the kernel at a randomized offset in physical memory.
*/
status = efi_random_alloc(*reserve_size, min_kimg_align,
- reserve_addr, phys_seed);
+ reserve_addr, phys_seed,
+ EFI_LOADER_CODE);
if (status != EFI_SUCCESS)
efi_warn("efi_random_alloc() failed: 0x%lx\n", status);
} else {
@@ -201,7 +202,8 @@ efi_status_t handle_kernel_image(unsigne
}

status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
- ULONG_MAX, min_kimg_align);
+ ULONG_MAX, min_kimg_align,
+ EFI_LOADER_CODE);

if (status != EFI_SUCCESS) {
efi_err("Failed to relocate kernel\n");
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -880,7 +880,8 @@ void efi_get_virtmap(efi_memory_desc_t *
efi_status_t efi_get_random_bytes(unsigned long size, u8 *out);

efi_status_t efi_random_alloc(unsigned long size, unsigned long align,
- unsigned long *addr, unsigned long random_seed);
+ unsigned long *addr, unsigned long random_seed,
+ int memory_type);

efi_status_t efi_random_get_seed(void);

@@ -907,7 +908,8 @@ efi_status_t efi_allocate_pages(unsigned
unsigned long max);

efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
- unsigned long max, unsigned long align);
+ unsigned long max, unsigned long align,
+ int memory_type);

efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
unsigned long *addr, unsigned long min);
--- a/drivers/firmware/efi/libstub/mem.c
+++ b/drivers/firmware/efi/libstub/mem.c
@@ -91,7 +91,8 @@ efi_status_t efi_allocate_pages(unsigned

if (EFI_ALLOC_ALIGN > EFI_PAGE_SIZE)
return efi_allocate_pages_aligned(size, addr, max,
- EFI_ALLOC_ALIGN);
+ EFI_ALLOC_ALIGN,
+ EFI_LOADER_DATA);

alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
--- a/drivers/firmware/efi/libstub/randomalloc.c
+++ b/drivers/firmware/efi/libstub/randomalloc.c
@@ -53,7 +53,8 @@ static unsigned long get_entry_num_slots
efi_status_t efi_random_alloc(unsigned long size,
unsigned long align,
unsigned long *addr,
- unsigned long random_seed)
+ unsigned long random_seed,
+ int memory_type)
{
unsigned long total_slots = 0, target_slot;
unsigned long total_mirrored_slots = 0;
@@ -118,7 +119,7 @@ efi_status_t efi_random_alloc(unsigned l
pages = size / EFI_PAGE_SIZE;

status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
- EFI_LOADER_DATA, pages, &target);
+ memory_type, pages, &target);
if (status == EFI_SUCCESS)
*addr = target;
break;