lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sun, 16 Apr 2023 14:07:29 +0200
From:   Ard Biesheuvel <ardb@...nel.org>
To:     linux-efi@...r.kernel.org
Cc:     linux-kernel@...r.kernel.org, Ard Biesheuvel <ardb@...nel.org>,
        Evgeniy Baskov <baskov@...ras.ru>,
        Borislav Petkov <bp@...en8.de>,
        Andy Lutomirski <luto@...nel.org>,
        Dave Hansen <dave.hansen@...ux.intel.com>,
        Ingo Molnar <mingo@...hat.com>,
        Peter Zijlstra <peterz@...radead.org>,
        Thomas Gleixner <tglx@...utronix.de>,
        Alexey Khoroshilov <khoroshilov@...ras.ru>,
        Peter Jones <pjones@...hat.com>,
        Gerd Hoffmann <kraxel@...hat.com>,
        Dave Young <dyoung@...hat.com>,
        Mario Limonciello <mario.limonciello@....com>,
        Kees Cook <keescook@...omium.org>,
        Tom Lendacky <thomas.lendacky@....com>,
        "Kirill A . Shutemov" <kirill.shutemov@...ux.intel.com>,
        Linus Torvalds <torvalds@...ux-foundation.org>
Subject: [RFC PATCH 3/3] efi/zboot: x86: Clear NX restrictions on populated code regions

Future EFI firmware will require the PE/COFF NX_COMPAT header flag to be
set in order to retain access to all system facilities while features
such as UEFI secure boot or TCG measured boot are enabled.

The consequence of setting this flag is that the EFI firmware image
loader may configure the page allocator to set the NX attribute on all
allocations requested by the image. This means we should clear this
attribute on all regions we allocate and expect to be able to execute
from.

In the x86 EFI zboot case, the only code we execute under EFI's 1:1
mapping that was not loaded by the image loader itself is the trampoline
that effectuates the switch between 4 and 5 level paging, and the part
of the loaded kernel image that runs before switching to its own page
tables.  So let's use the EFI memory attributes protocol to clear the NX
attribute on these regions.

Whether or not setting the read-only attribute first is required is
unclear at this point. Given that the kernel startup code uses two
different executable sections before switching to its own page tables
(normal text and inittext, with a writable data section in between),
this would require some minor reorganization of the kernel memory map.

Signed-off-by: Ard Biesheuvel <ardb@...nel.org>
---
 arch/x86/kernel/head_64.S                |  4 +++
 drivers/firmware/efi/libstub/x86-zboot.c | 27 ++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 4ae067852fb28663..38897ac51f13bb55 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -74,6 +74,10 @@ SYM_CODE_START_NOALIGN(startup_64)
 	 */
 	.org	startup_64 + 0x10 - 3, BYTES_NOP1
 	nopl	(_end - startup_64)(%rax)
+
+	/* put the size of the initial executable mapping at offset 0x20 */
+	.org	startup_64 + 0x20 - 3, BYTES_NOP1
+	nopl	(_einittext - startup_64)(%rax)
 #endif
 	leaq	_text(%rip), %rdi
 
diff --git a/drivers/firmware/efi/libstub/x86-zboot.c b/drivers/firmware/efi/libstub/x86-zboot.c
index 16e8b315892dedda..70668104804fb050 100644
--- a/drivers/firmware/efi/libstub/x86-zboot.c
+++ b/drivers/firmware/efi/libstub/x86-zboot.c
@@ -60,10 +60,33 @@ efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr)
 	return status;
 }
 
+static void efi_remap_exec(unsigned long base, unsigned long size)
+{
+	static efi_memory_attribute_protocol_t *memattr = (void *)ULONG_MAX;
+	efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+	efi_status_t status;
+
+	if (memattr == (void *)ULONG_MAX) {
+		memattr = NULL;
+		status = efi_bs_call(locate_protocol, &guid, NULL,
+				     (void **)&memattr);
+		if (status != EFI_SUCCESS)
+			return;
+	} else if (!memattr) {
+		return;
+	}
+
+	status = memattr->clear_memory_attributes(memattr, base, size,
+						  EFI_MEMORY_XP);
+	if (status != EFI_SUCCESS)
+		efi_warn("Failed to clear NX attribute on code region\n");
+}
+
 void efi_cache_sync_image(unsigned long image_base, unsigned long alloc_size)
 {
 	const u32 payload_size = *(u32 *)(_gzdata_end - 4);
 	const u32 image_size = *(u32 *)(image_base + 0x10);
+	const u32 code_size = *(u32 *)(image_base + 0x20);
 	const s32 *reloc = (s32 *)(image_base + payload_size);
 	u64 va_offset = __START_KERNEL - image_base;
 	u64 range, delta;
@@ -107,6 +130,8 @@ void efi_cache_sync_image(unsigned long image_base, unsigned long alloc_size)
 		*(u64 *)((s64)*reloc - va_offset) += delta;
 
 	efi_free(alloc_size - image_size, image_base + image_size);
+
+	efi_remap_exec(image_base, PAGE_ALIGN(code_size));
 }
 
 static void __naked tmpl_toggle(void *cr3, void *gdt)
@@ -197,6 +222,8 @@ static efi_status_t efi_setup_5level_paging(void)
 	 */
 	*(u32 *)&la57_code[tmpl_size - 6] += (u64)la57_code;
 
+	efi_remap_exec((unsigned long)la57_code, PAGE_SIZE);
+
 	return EFI_SUCCESS;
 }
 
-- 
2.39.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ