@@ -651,3 +651,70 @@ efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
651
651
652
652
return status ;
653
653
}
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