[PATCH v2 21/23] efi/x86: Explicitly set sections memory attributes

From: Evgeniy Baskov
Date: Tue Oct 25 2022 - 10:15:14 EST


Explicitly change sections memory attributes in efi_pe_entry in case
of incorrect EFI implementations and to reduce access rights to
compressed kernel blob. By default it is set executable due to
restriction in maximum number of sections that can fit before zero
page.

Signed-off-by: Evgeniy Baskov <baskov@xxxxxxxxx>
---
drivers/firmware/efi/libstub/x86-stub.c | 56 +++++++++++++++++++++++++
1 file changed, 56 insertions(+)

diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index 4d9588d33479..d9bb9125d518 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -27,6 +27,12 @@ const efi_dxe_services_table_t *efi_dxe_table;
extern u32 image_offset;
static efi_loaded_image_t *image = NULL;

+extern char _head[], _ehead[];
+extern char _compressed[], _ecompressed[];
+extern char _text[], _etext[];
+extern char _rodata[], _erodata[];
+extern char _data[];
+
static efi_status_t
preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
{
@@ -343,6 +349,54 @@ static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)
asm("hlt");
}

+
+/*
+ * Manually setup memory protection attributes for each ELF section
+ * since we cannot do it properly by using PE sections.
+ */
+static void setup_sections_memory_protection(void *image_base,
+ unsigned long init_size)
+{
+#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES
+ efi_dxe_table = get_efi_config_table(EFI_DXE_SERVICES_TABLE_GUID);
+
+ if (!efi_dxe_table ||
+ efi_dxe_table->hdr.signature != EFI_DXE_SERVICES_TABLE_SIGNATURE) {
+ efi_warn("Unable to locate EFI DXE services table\n");
+ efi_dxe_table = NULL;
+ return;
+ }
+
+ /* .setup [image_base, _head] */
+ efi_adjust_memory_range_protection((unsigned long)image_base,
+ (unsigned long)_head - (unsigned long)image_base,
+ EFI_MEMORY_RO | EFI_MEMORY_XP);
+ /* .head.text [_head, _ehead] */
+ efi_adjust_memory_range_protection((unsigned long)_head,
+ (unsigned long)_ehead - (unsigned long)_head,
+ EFI_MEMORY_RO);
+ /* .rodata..compressed [_compressed, _ecompressed] */
+ efi_adjust_memory_range_protection((unsigned long)_compressed,
+ (unsigned long)_ecompressed - (unsigned long)_compressed,
+ EFI_MEMORY_RO | EFI_MEMORY_XP);
+ /* .text [_text, _etext] */
+ efi_adjust_memory_range_protection((unsigned long)_text,
+ (unsigned long)_etext - (unsigned long)_text,
+ EFI_MEMORY_RO);
+ /* .rodata [_rodata, _erodata] */
+ efi_adjust_memory_range_protection((unsigned long)_rodata,
+ (unsigned long)_erodata - (unsigned long)_rodata,
+ EFI_MEMORY_RO | EFI_MEMORY_XP);
+ /* .data, .bss [_data, image_base + init_size] */
+ efi_adjust_memory_range_protection((unsigned long)_data,
+ (unsigned long)image_base + init_size - (unsigned long)_rodata,
+ EFI_MEMORY_XP);
+#else
+ (void)image_base;
+ (void)init_size;
+#endif
+}
+
void __noreturn efi_stub_entry(efi_handle_t handle,
efi_system_table_t *sys_table_arg,
struct boot_params *boot_params);
@@ -396,6 +450,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
memcpy(&hdr->jump, image_base + 0x1000,
sizeof(struct setup_header) - offsetof(struct setup_header, jump));

+ setup_sections_memory_protection(image_base, hdr->init_size);
+
/*
* Fill out some of the header fields ourselves because the
* EFI firmware loader doesn't load the first sector.
--
2.37.4