UEFI specification does not guarantee that memory used for trampoline by GRUB would be executable. Some stricter implementations set NX flag for most regions.
Explicitly mark memory range where trampoline would be allocated as writable and executable using DXE services on x86-efi variations. Avoid modification if not necessary and only modify system memory to reduce the possibility to encounter firmware bugs. Signed-off-by: Baskov Evgeniy <bas...@ispras.ru> diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index d8e411454..f6d1170d1 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -230,6 +230,71 @@ stop_broadcom (void) #endif +static void +unprotect_memory_range (grub_efi_physical_address_t start, + grub_efi_physical_address_t end) +{ + static grub_efi_guid_t dxe_guid = GRUB_EFI_DXE_SERVICES_TABLE_GUID; + grub_efi_physical_address_t rounded_start, rounded_end, next; + grub_efi_physical_address_t unprotect_start, unprotect_end; + grub_efi_dxe_services_t *dxe; + grub_efi_gcd_memory_space_descriptor_t desc; + grub_efi_status_t status; + + dxe = grub_efi_get_config_table (&dxe_guid); + if (dxe == NULL || dxe->hdr.signature != GRUB_EFI_DXE_SERVICES_SIGNATURE) + return; + + rounded_start = start & ~GRUB_EFI_PAGE_SIZE; + rounded_end = (end + GRUB_EFI_PAGE_SIZE - 1) & ~GRUB_EFI_PAGE_SIZE; + + /* + * Don't modify memory region attributes, they are + * already suitable, to lower the possibility to + * encounter firmware bugs. + */ + + for (; start < end; start = next) + { + status = efi_call_2 (dxe->get_memory_space_descriptor, start, &desc); + + if (status != GRUB_EFI_SUCCESS) + return; + + next = desc.base_address + desc.length; + + /* + * Only system memory is suitable for trampoline/kernel image placement, + * so only this type of memory needs its attributes to be modified. + */ + + if (desc.gcd_memory_type != GRUB_EFI_GCD_MEMORY_TYPE_SYSTEM_MEMORY || + (desc.attributes & (GRUB_EFI_MEMORY_RO | GRUB_EFI_MEMORY_XP)) == 0) + continue; + + unprotect_start = rounded_start; + if (unprotect_start < desc.base_address) + unprotect_start = desc.base_address; + + unprotect_end = rounded_end; + if (unprotect_end > next) + unprotect_end = next; + + status = efi_call_3 (dxe->set_memory_space_attributes, + unprotect_start, + unprotect_end - unprotect_start, + GRUB_EFI_MEMORY_WB); + + if (status != GRUB_EFI_SUCCESS) + { + grub_printf ("Cannot change memory attributes in range [0x%lX, 0x%lX): 0x%lX\n", + (long)unprotect_start, + (long)unprotect_end, + (long)status); + } + } +} + grub_err_t grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf, grub_efi_uintn_t *map_key, @@ -239,6 +304,8 @@ grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf, grub_efi_boot_services_t *b; grub_efi_status_t status; + unprotect_memory_range(0x1000, 0xa0000); + #if defined (__i386__) || defined (__x86_64__) const grub_uint16_t apple[] = { 'A', 'p', 'p', 'l', 'e' }; int is_apple; -- 2.35.1 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel