@@ -651,3 +651,70 @@ efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
651651
652652 return status ;
653653}
654+
655+ /**
656+ * efi_remap_image - Remap a loaded image with the appropriate permissions
657+ * for code and data
658+ *
659+ * @image_base: the base of the image in memory
660+ * @alloc_size: the size of the area in memory occupied by the image
661+ * @code_size: the size of the leading part of the image containing code
662+ * and read-only data
663+ *
664+ * efi_remap_image() uses the EFI memory attribute protocol to remap the code
665+ * region of the loaded image read-only/executable, and the remainder
666+ * read-write/non-executable. The code region is assumed to start at the base
667+ * of the image, and will therefore cover the PE/COFF header as well.
668+ */
669+ void efi_remap_image (unsigned long image_base , unsigned alloc_size ,
670+ unsigned long code_size )
671+ {
672+ efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID ;
673+ efi_memory_attribute_protocol_t * memattr ;
674+ efi_status_t status ;
675+ u64 attr ;
676+
677+ /*
678+ * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's
679+ * invoke it to remap the text/rodata region of the decompressed image
680+ * as read-only and the data/bss region as non-executable.
681+ */
682+ status = efi_bs_call (locate_protocol , & guid , NULL , (void * * )& memattr );
683+ if (status != EFI_SUCCESS )
684+ return ;
685+
686+ // Get the current attributes for the entire region
687+ status = memattr -> get_memory_attributes (memattr , image_base ,
688+ alloc_size , & attr );
689+ if (status != EFI_SUCCESS ) {
690+ efi_warn ("Failed to retrieve memory attributes for image region: 0x%lx\n" ,
691+ status );
692+ return ;
693+ }
694+
695+ // Mark the code region as read-only
696+ status = memattr -> set_memory_attributes (memattr , image_base , code_size ,
697+ EFI_MEMORY_RO );
698+ if (status != EFI_SUCCESS ) {
699+ efi_warn ("Failed to remap code region read-only\n" );
700+ return ;
701+ }
702+
703+ // If the entire region was already mapped as non-exec, clear the
704+ // attribute from the code region. Otherwise, set it on the data
705+ // region.
706+ if (attr & EFI_MEMORY_XP ) {
707+ status = memattr -> clear_memory_attributes (memattr , image_base ,
708+ code_size ,
709+ EFI_MEMORY_XP );
710+ if (status != EFI_SUCCESS )
711+ efi_warn ("Failed to remap code region executable\n" );
712+ } else {
713+ status = memattr -> set_memory_attributes (memattr ,
714+ image_base + code_size ,
715+ alloc_size - code_size ,
716+ EFI_MEMORY_XP );
717+ if (status != EFI_SUCCESS )
718+ efi_warn ("Failed to remap data region non-executable\n" );
719+ }
720+ }
0 commit comments