diff --git a/0370-Set-correctly-the-memory-attributes-for-the-kernel-P.patch b/0370-Set-correctly-the-memory-attributes-for-the-kernel-P.patch new file mode 100644 index 0000000000000000000000000000000000000000..b216fb72b6595283a8dee842fb56d0f2a5ee3212 --- /dev/null +++ b/0370-Set-correctly-the-memory-attributes-for-the-kernel-P.patch @@ -0,0 +1,282 @@ +From ab36bcf62fa3e10cf47fee40893ec917f98ab4c3 Mon Sep 17 00:00:00 2001 +From: Leo Sandoval +Subject: [PATCH] Set correctly the memory attributes for the kernel PE sections (Ported with Inline API) + +Ported to apply to grub-core/loader/efi/linux.c in upstream-based trees. +Includes inline definitions of Memory Attribute Protocol APIs to avoid dependency on +other patches modifying api.h and mm.h/mm.c. +Enforces memory attributes on the loaded EFI image before starting it. + +--- + grub-core/loader/efi/linux.c | 241 +++++++++++++++++++++++++++++++++++ + 1 file changed, 241 insertions(+) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index bfbd95a..735a85e 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); +@@ -87,6 +88,243 @@ static grub_efi_load_file2_t initrd_lf2 = { + grub_efi_initrd_load_file2 + }; + ++/* ++ * Inline definitions for Memory Attribute Protocol to avoid dependency on ++ * other patches modifying api.h and mm.h/mm.c ++ */ ++#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \ ++ { 0xf4560cf6, 0x40ec, 0x4b4a, \ ++ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \ ++ } ++ ++typedef struct grub_efi_memory_attribute_protocol ++{ ++ grub_efi_status_t (*get_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t *attributes); ++ grub_efi_status_t (*set_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++ grub_efi_status_t (*clear_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++} grub_efi_memory_attribute_protocol_t; ++ ++#define GRUB_MEM_ATTR_R 0x0000000000000004LLU ++#define GRUB_MEM_ATTR_W 0x0000000000000002LLU ++#define GRUB_MEM_ATTR_X 0x0000000000000001LLU ++ ++static inline grub_uint64_t ++grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_EFI_MEMORY_RP | ++ GRUB_EFI_MEMORY_RO | ++ GRUB_EFI_MEMORY_XP; ++ ++ if (attrs & GRUB_MEM_ATTR_R) ++ ret &= ~GRUB_EFI_MEMORY_RP; ++ ++ if (attrs & GRUB_MEM_ATTR_W) ++ ret &= ~GRUB_EFI_MEMORY_RO; ++ ++ if (attrs & GRUB_MEM_ATTR_X) ++ ret &= ~GRUB_EFI_MEMORY_XP; ++ ++ return ret; ++} ++ ++static inline grub_uint64_t ++uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ ++ if (attrs & GRUB_EFI_MEMORY_RP) ++ ret &= ~GRUB_MEM_ATTR_R; ++ ++ if (attrs & GRUB_EFI_MEMORY_RO) ++ ret &= ~GRUB_MEM_ATTR_W; ++ ++ if (attrs & GRUB_EFI_MEMORY_XP) ++ ret &= ~GRUB_MEM_ATTR_X; ++ ++ return ret; ++} ++ ++static inline grub_err_t ++grub_efi_status_to_err_local (grub_efi_status_t status) ++{ ++ grub_err_t err; ++ switch (status) ++ { ++ case GRUB_EFI_SUCCESS: ++ err = GRUB_ERR_NONE; ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ default: ++ err = GRUB_ERR_BAD_ARGUMENT; ++ break; ++ case GRUB_EFI_OUT_OF_RESOURCES: ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ break; ++ case GRUB_EFI_DEVICE_ERROR: ++ err = GRUB_ERR_IO; ++ break; ++ case GRUB_EFI_WRITE_PROTECTED: ++ err = GRUB_ERR_WRITE_ERROR; ++ break; ++ case GRUB_EFI_SECURITY_VIOLATION: ++ err = GRUB_ERR_ACCESS_DENIED; ++ break; ++ case GRUB_EFI_NOT_FOUND: ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ break; ++ case GRUB_EFI_ABORTED: ++ err = GRUB_ERR_WAIT; ++ break; ++ } ++ return err; ++} ++ ++static grub_err_t ++grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NONE; /* Fallback: pretend everything is fine if protocol missing */ ++ ++ efi_status = proto->get_memory_attributes( ++ proto, physaddr, size, attrs); ++ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs); ++ ++ return grub_efi_status_to_err_local (efi_status); ++} ++ ++static grub_err_t ++grub_update_mem_attrs (grub_addr_t addr, grub_size_t size, ++ grub_uint64_t set_attrs, grub_uint64_t clear_attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS; ++ grub_uint64_t uefi_set_attrs, uefi_clear_attrs; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NONE; ++ ++ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs); ++ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs); ++ ++ if (uefi_set_attrs) ++ efi_status = proto->set_memory_attributes( ++ proto, physaddr, size, uefi_set_attrs); ++ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs) ++ efi_status = proto->clear_memory_attributes( ++ proto, physaddr, size, uefi_clear_attrs); ++ ++ return grub_efi_status_to_err_local (efi_status); ++} ++ ++static grub_err_t ++grub_efi_mem_set_att (grub_addr_t k_address, grub_size_t k_size) ++{ ++ grub_uint64_t default_set_attrs = GRUB_MEM_ATTR_R | GRUB_MEM_ATTR_W | GRUB_MEM_ATTR_X; ++ grub_uint64_t default_clear_attrs = 0; ++ grub_uint64_t kernel_set_attrs = default_set_attrs; ++ grub_uint64_t kernel_clear_attrs = default_clear_attrs; ++ grub_uint64_t attrs; ++ ++ struct grub_msdos_image_header *header; ++ struct grub_pe_image_header *pe_image_header; ++ struct grub_pe32_coff_header *coff_header; ++ struct grub_pe32_section_table *section, *sections; ++ grub_uint16_t i; ++ grub_size_t sz; ++ ++ header = (struct grub_msdos_image_header *)k_address; ++ ++ if (grub_add ((grub_addr_t) header, header->pe_image_header_offset, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE image header address calculation")); ++ ++ pe_image_header = (struct grub_pe_image_header *) (sz); ++ ++ if (pe_image_header > (k_address k_size)) ++ return grub_error (GRUB_ERR_BAD_OS, N_("PE image header address is invalid")); ++ ++ if (grub_memcmp (pe_image_header->signature, GRUB_PE32_SIGNATURE, ++ GRUB_PE32_SIGNATURE_SIZE) != 0) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); ++ ++ coff_header = &(pe_image_header->coff_header); ++ grub_dprintf ("nx", "coff_header 0x%"PRIxGRUB_ADDR" machine %08x\n", (grub_addr_t)coff_header, coff_header->machine); ++ ++ if (grub_add ((grub_addr_t) coff_header, sizeof (*coff_header), &sz) || ++ grub_add (sz, coff_header->optional_header_size, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE sections calculation")); ++ ++ sections = (struct grub_pe32_section_table *) (sz); ++ ++ if (sections > (k_address k_size)) ++ return grub_error (GRUB_ERR_BAD_OS, N_("Section address is invalid")); ++ ++ /* Parse the PE, remove W for code section, remove X for data sections, RO for the rest */ ++ for (i = 0, section = sections; i < coff_header->num_sections; i++, section++) ++ { ++ kernel_set_attrs = default_set_attrs; ++ kernel_clear_attrs = default_clear_attrs; ++ ++ /* Always enforce NX protection */ ++ if (section->characteristics & GRUB_PE32_SCN_MEM_EXECUTE) ++ { ++ /* RX section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_W; ++ } ++ else if (section->characteristics & GRUB_PE32_SCN_MEM_WRITE) ++ { ++ /* RW section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_X; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ else ++ { ++ /* RO section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W & ~GRUB_MEM_ATTR_X; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_X | GRUB_MEM_ATTR_W ; ++ } ++ ++ /* Make sure we are inside range */ ++ if (grub_add ((grub_addr_t) k_address, section->raw_data_offset, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE Executable section calculation")); ++ ++ grub_update_mem_attrs (sz, section->raw_data_size, kernel_set_attrs, kernel_clear_attrs); ++ ++ grub_get_mem_attrs (sz, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for section %s 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ section->name, ++ (grub_addr_t)sz, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + grub_err_t + grub_arch_efi_linux_load_image_header (grub_file_t file, + struct linux_arch_kernel_header * lh) +@@ -236,6 +474,9 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) + + grub_dprintf ("linux", "starting image %p\n", image_handle); + status = b->start_image (image_handle, 0, NULL); ++ /* Fix memory attributes before starting image */ ++ if (loaded_image && loaded_image->image_base) ++ grub_efi_mem_set_att ((grub_addr_t) loaded_image->image_base, loaded_image->image_size); + + /* When successful, not reached */ + grub_error (GRUB_ERR_BAD_OS, "start_image() returned 0x%" PRIxGRUB_EFI_UINTN_T, status); +-- +2.41.3 + diff --git a/grub.patches b/grub.patches index 5e034c21572de93902b322adcccb4038e804d0c0..210184bf3a280747ee0872b2e78862ef6438bf58 100644 --- a/grub.patches +++ b/grub.patches @@ -362,3 +362,4 @@ Patch0366: 0366-disk-cryptodisk-Add-the-erase-secrets-function.patch Patch0367: 0367-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch Patch0368: 0368-cryptocheck-Add-quiet-option.patch Patch0369: 0369-commands-efi-tpm-Re-enable-measurements-on-confident.patch +Patch0370: 0370-Set-correctly-the-memory-attributes-for-the-kernel-P.patch diff --git a/grub2.spec b/grub2.spec index cfad11a61f0f3b84b05451c90aae15cfd2d8cf70..11ab3928b8c05d41b064ce42e65688a6bd32917f 100644 --- a/grub2.spec +++ b/grub2.spec @@ -140,7 +140,7 @@ Summary: A Multiboot boot loader with support for Linux Name: grub2 Version: 2.12 -Release: 19%{?dist} +Release: 20%{?dist} License: GPLv3+ URL: http://www.gnu.org/software/grub/ Source0: https://ftp.gnu.org/gnu/grub/grub-%{version}.tar.xz @@ -841,6 +841,10 @@ mv %{efi_esp_dir}/grub.cfg.stb %{efi_esp_dir}/grub.cfg %endif %changelog +* Tue Dec 30 2025 wynnfeng - 2.12-20 +- [Type] bugfix +- [DESC] Set correctly the memory attributes for the kernel PE sections + * Fri Dec 19 2025 xiaoyunzhao - 2.12-19 - [Type] bugfix - [DESC] Fixed a bug in the video module that caused page faults on some platforms.