efi: libstub: use EFI_LOADER_CODE region when moving the kernel in memory
authorArd Biesheuvel <ardb@kernel.org>
Tue, 2 Aug 2022 09:00:16 +0000 (11:00 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Fri, 18 Nov 2022 08:14:08 +0000 (09:14 +0100)
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>
drivers/firmware/efi/libstub/alignedmem.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/mem.c
drivers/firmware/efi/libstub/randomalloc.c

index 1de9878ddd3a2fbbeea8c00a7fce98f00beb862c..174832661251e84611680592e9a7e4dc10de63f6 100644 (file)
@@ -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(unsigned long size, unsigned long *addr,
        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;
index c14028b625b4b92fbaf34209a2625ec876ea3462..7f0aab3a8ab302d6f8ed4fa2b8cf62deeb2cb3ad 100644 (file)
@@ -102,7 +102,8 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                 * 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 {
@@ -123,7 +124,8 @@ 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,
+                                                   EFI_LOADER_CODE);
 
                if (status != EFI_SUCCESS) {
                        efi_err("Failed to relocate kernel\n");
index 21b01d6c77ba3a84973456f2c9df86e0058f1b4f..e85916ed5311139380f53f99789eb8c429332515 100644 (file)
@@ -880,7 +880,8 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
 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 check_platform_features(void);
 
@@ -905,7 +906,8 @@ efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
                                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);
index 45841ef55a9f6ba284ec7f4bd34fc24a6b91451e..03d147f17185b329a54b4362bb7b2dae3e4565fc 100644 (file)
@@ -91,7 +91,8 @@ efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
 
        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,
index 9fb5869896be7340c9bb7f4141c4cf93c9a4bbca..ec44bb7e092faf7d95a80319ec14639c0519e3fd 100644 (file)
@@ -53,7 +53,8 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
 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 long size,
                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;