public inbox for linux-efi@vger.kernel.org
 help / color / mirror / Atom feed
From: Baskov Evgeniy <baskov@ispras.ru>
To: Ard Biesheuvel <ardb@kernel.org>
Cc: Baskov Evgeniy <baskov@ispras.ru>,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	x86@kernel.org, linux-efi@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH RFC v2 2/2] libstub: ensure allocated memory to be executable
Date: Thu, 24 Feb 2022 18:43:30 +0300	[thread overview]
Message-ID: <20220224154330.26564-3-baskov@ispras.ru> (raw)
In-Reply-To: <20220224154330.26564-1-baskov@ispras.ru>

There are UEFI versions that restrict execution of memory regions,
preventing the kernel from booting. Parts that needs to be executable
are:

* Area used for trampoline placement.
* All memory regions that the kernel may be relocated before
  and during extraction.

Use DXE services to ensure aforementioned address ranges
to be executable.

Signed-off-by: Baskov Evgeniy <baskov@ispras.ru>

diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index 01ddd4502e28..ca7d5379b480 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -22,6 +22,7 @@
 #define MAXMEM_X86_64_4LEVEL (1ull << 46)
 
 const efi_system_table_t *efi_system_table;
+const efi_dxe_services_table_t *efi_dxe_table;
 extern u32 image_offset;
 static efi_loaded_image_t *image = NULL;
 
@@ -211,9 +212,41 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
 	}
 }
 
+
+static void unprotect_memory_range(unsigned long base, unsigned long size)
+{
+	unsigned long rounded_base, rounded_size;
+	efi_status_t res;
+
+	if (efi_dxe_table == NULL)
+		return;
+
+	rounded_base = rounddown(base, EFI_PAGE_SIZE);
+	rounded_size = roundup(base + size, EFI_PAGE_SIZE) - rounded_base;
+
+	res = efi_dxe_call(set_memory_space_attributes,
+			   rounded_base, rounded_size, EFI_MEMORY_WB);
+	if (res != EFI_SUCCESS) {
+		efi_warn("Unable to unprotect memory range [%08lx,%08lx]: %d\n",
+			 base, size + base, (int)res);
+	}
+}
+
+/*
+ * Trampoline takes 2 pages and can be loaded in first megabyte of memory
+ * with its end placed between 128k and 640k where BIOS might start
+ */
+
+#define TRAMPOLINE_PLACEMENT_BASE ((128 - 8)*1024)
+#define TRAMPOLINE_PLACEMENT_SIZE (640*1024 - (128 - 8)*1024)
+
+void startup_32(struct boot_params *boot_params);
+
 static const efi_char16_t apple[] = L"Apple";
 
-static void setup_quirks(struct boot_params *boot_params)
+static void setup_quirks(struct boot_params *boot_params,
+			 unsigned long image_base,
+			 unsigned long image_size)
 {
 	efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
 		efi_table_attr(efi_system_table, fw_vendor);
@@ -222,6 +255,31 @@ static void setup_quirks(struct boot_params *boot_params)
 		if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
 			retrieve_apple_device_properties(boot_params);
 	}
+
+	/*
+	 * Allow execution of possible trampoline used
+	 * for switching between 4- and 5-level page tables
+	 * and relocated kernel image.
+	 */
+
+	unprotect_memory_range(TRAMPOLINE_PLACEMENT_BASE,
+	                       TRAMPOLINE_PLACEMENT_SIZE);
+
+#ifdef CONFIG_64BIT
+	if (image_base != (unsigned long)startup_32)
+		unprotect_memory_range(image_base, image_size);
+#else
+	/*
+	 * Clear protection flags on a whole range of possible
+	 * addresses used for KASLR. We don't need to do that
+	 * on x86_64, since KASLR/extraction is performed after
+	 * dedicated identity page tables are built and we only
+	 * need to remove possible protection on relocated image
+	 * itself disregarding further relocations.
+	 */
+	unprotect_memory_range(LOAD_PHYSICAL_ADDR,
+			       KERNEL_IMAGE_SIZE - LOAD_PHYSICAL_ADDR);
+#endif
 }
 
 /*
@@ -341,8 +399,6 @@ static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)
 		asm("hlt");
 }
 
-void startup_32(struct boot_params *boot_params);
-
 void __noreturn efi_stub_entry(efi_handle_t handle,
 			       efi_system_table_t *sys_table_arg,
 			       struct boot_params *boot_params);
@@ -677,11 +733,18 @@ unsigned long efi_main(efi_handle_t handle,
 	efi_status_t status;
 
 	efi_system_table = sys_table_arg;
-
 	/* Check if we were booted by the EFI firmware */
 	if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
 		efi_exit(handle, EFI_INVALID_PARAMETER);
 
+	efi_dxe_table = get_efi_config_table(EFI_DXE_SERVICES_TABLE_GUID);
+
+	if (efi_dxe_table == NULL ||
+	    efi_dxe_table->hdr.signature != EFI_DXE_SERVICES_TABLE_SIGNATURE) {
+		efi_warn("Unable to locate EFI DXE services table\n");
+		efi_dxe_table = NULL;
+	}
+
 	/*
 	 * If the kernel isn't already loaded at a suitable address,
 	 * relocate it.
@@ -791,7 +854,7 @@ unsigned long efi_main(efi_handle_t handle,
 
 	setup_efi_pci(boot_params);
 
-	setup_quirks(boot_params);
+	setup_quirks(boot_params, bzimage_addr, buffer_end - buffer_start);
 
 	status = exit_boot(boot_params, handle);
 	if (status != EFI_SUCCESS) {
-- 
2.35.1


  parent reply	other threads:[~2022-02-24 15:54 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-24 15:43 [PATCH RFC v2 0/2] Handle UEFI NX-restricted page tables Baskov Evgeniy
2022-02-24 15:43 ` [PATCH RFC v2 1/2] libstub: declare DXE services table Baskov Evgeniy
2022-02-24 15:43 ` Baskov Evgeniy [this message]
2022-02-28 16:45 ` [PATCH RFC v2 0/2] Handle UEFI NX-restricted page tables Ard Biesheuvel
2022-02-28 18:30   ` Matthew Garrett
2022-03-03 13:42     ` baskov
2022-03-03 20:47       ` Matthew Garrett
2022-03-17 13:26         ` baskov
2022-03-18 16:37         ` Peter Jones
2022-03-24 16:39           ` baskov
2022-03-25  8:06             ` Ard Biesheuvel
2022-04-13 17:50               ` Ard Biesheuvel
2022-03-29 18:47             ` Peter Jones
2022-03-29 18:47               ` [PATCH] x86: Set the NX-compatibility flag in the PE header Peter Jones
2022-04-13 17:48                 ` Ard Biesheuvel
2022-03-03 14:15   ` [PATCH RFC v2 0/2] Handle UEFI NX-restricted page tables baskov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220224154330.26564-3-baskov@ispras.ru \
    --to=baskov@ispras.ru \
    --cc=ardb@kernel.org \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=linux-efi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox