summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Smith-Denny <osde@linux.microsoft.com>2024-03-29 13:21:29 -0700
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-03-29 23:56:16 +0000
commit37f63deeefa89b7ac28285bc59eca22a5c00eb92 (patch)
tree6779ee2e296c9145962440b8a4d2008fe4565027
parent596f856c13fb9f3a6afb17573a762c6f02654a92 (diff)
downloadedk2-37f63deeefa89b7ac28285bc59eca22a5c00eb92.tar.gz
edk2-37f63deeefa89b7ac28285bc59eca22a5c00eb92.tar.bz2
edk2-37f63deeefa89b7ac28285bc59eca22a5c00eb92.zip
MdeModulePkg: MemoryProtection: Use ImageRecordPropertiesLib
The functionality to create and delete Image Records has been consolidated in a library and ensured that MemoryProtection.c's usage is encapsulated there. This patch moves MemoryProtection.c to reuse the code in the lib and to prevent issues in the future where code is updated in one place but not the other. Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Taylor Beebe <taylor.d.beebe@gmail.com> Acked-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Oliver Smith-Denny <osde@linux.microsoft.com>
-rw-r--r--MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c241
1 files changed, 28 insertions, 213 deletions
diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
index eb243a0137..2c069cc12c 100644
--- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
+++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
@@ -281,80 +281,43 @@ SetUefiImageProtectionAttributes (
}
/**
- Return if the PE image section is aligned.
+ Return the section alignment requirement for the PE image section type.
- @param[in] SectionAlignment PE/COFF section alignment
- @param[in] MemoryType PE/COFF image memory type
+ @param[in] MemoryType PE/COFF image memory type
+
+ @retval The required section alignment for this memory type
- @retval TRUE The PE image section is aligned.
- @retval FALSE The PE image section is not aligned.
**/
-BOOLEAN
-IsMemoryProtectionSectionAligned (
- IN UINT32 SectionAlignment,
+STATIC
+UINT32
+GetMemoryProtectionSectionAlignment (
IN EFI_MEMORY_TYPE MemoryType
)
{
- UINT32 PageAlignment;
+ UINT32 SectionAlignment;
switch (MemoryType) {
case EfiRuntimeServicesCode:
case EfiACPIMemoryNVS:
case EfiReservedMemoryType:
- PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
break;
case EfiRuntimeServicesData:
ASSERT (FALSE);
- PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
break;
case EfiBootServicesCode:
case EfiLoaderCode:
- PageAlignment = EFI_PAGE_SIZE;
+ SectionAlignment = EFI_PAGE_SIZE;
break;
case EfiACPIReclaimMemory:
default:
ASSERT (FALSE);
- PageAlignment = EFI_PAGE_SIZE;
+ SectionAlignment = EFI_PAGE_SIZE;
break;
}
- if ((SectionAlignment & (PageAlignment - 1)) != 0) {
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
-/**
- Free Image record.
-
- @param[in] ImageRecord A UEFI image record
-**/
-VOID
-FreeImageRecord (
- IN IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- LIST_ENTRY *CodeSegmentListHead;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
-
- CodeSegmentListHead = &ImageRecord->CodeSegmentList;
- while (!IsListEmpty (CodeSegmentListHead)) {
- ImageRecordCodeSection = CR (
- CodeSegmentListHead->ForwardLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- RemoveEntryList (&ImageRecordCodeSection->Link);
- FreePool (ImageRecordCodeSection);
- }
-
- if (ImageRecord->Link.ForwardLink != NULL) {
- RemoveEntryList (&ImageRecord->Link);
- }
-
- FreePool (ImageRecord);
+ return SectionAlignment;
}
/**
@@ -369,19 +332,10 @@ ProtectUefiImage (
IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
)
{
- VOID *ImageAddress;
- EFI_IMAGE_DOS_HEADER *DosHdr;
- UINT32 PeCoffHeaderOffset;
- UINT32 SectionAlignment;
- EFI_IMAGE_SECTION_HEADER *Section;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
- UINT8 *Name;
- UINTN Index;
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- CHAR8 *PdbPointer;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- BOOLEAN IsAligned;
- UINT32 ProtectionPolicy;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ UINT32 ProtectionPolicy;
+ EFI_STATUS Status;
+ UINT32 RequiredAlignment;
DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));
DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));
@@ -406,161 +360,22 @@ ProtectUefiImage (
return;
}
- ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
-
- //
- // Step 1: record whole region
- //
- ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase;
- ImageRecord->ImageSize = LoadedImage->ImageSize;
-
- ImageAddress = LoadedImage->ImageBase;
-
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageAddress);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
- }
-
- //
- // Check PE/COFF image
- //
- DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress;
- PeCoffHeaderOffset = 0;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- PeCoffHeaderOffset = DosHdr->e_lfanew;
- }
+ RequiredAlignment = GetMemoryProtectionSectionAlignment (LoadedImage->ImageCodeType);
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset);
- if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
- DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
- // It might be image in SMM.
- goto Finish;
- }
-
- //
- // Get SectionAlignment
- //
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
- } else {
- SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
- }
-
- IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType);
- if (!IsAligned) {
- DEBUG ((
- DEBUG_VERBOSE,
- "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n",
- SectionAlignment
- ));
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageAddress);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
- }
-
- goto Finish;
- }
-
- Section = (EFI_IMAGE_SECTION_HEADER *)(
- (UINT8 *)(UINTN)ImageAddress +
- PeCoffHeaderOffset +
- sizeof (UINT32) +
- sizeof (EFI_IMAGE_FILE_HEADER) +
- Hdr.Pe32->FileHeader.SizeOfOptionalHeader
- );
- ImageRecord->CodeSegmentCount = 0;
- InitializeListHead (&ImageRecord->CodeSegmentList);
- for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
- Name = Section[Index].Name;
- DEBUG ((
- DEBUG_VERBOSE,
- " Section - '%c%c%c%c%c%c%c%c'\n",
- Name[0],
- Name[1],
- Name[2],
- Name[3],
- Name[4],
- Name[5],
- Name[6],
- Name[7]
- ));
-
- //
- // Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE
- // can always be mapped read-only, classify a section as a code section only
- // if it has the executable attribute set and the writable attribute cleared.
- //
- // This adheres more closely to the PE/COFF spec, and avoids issues with
- // Linux OS loaders that may consist of a single read/write/execute section.
- //
- if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {
- DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
- DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
- DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
- DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
- DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
- DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
- DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
- DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
- DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
-
- //
- // Step 2: record code section
- //
- ImageRecordCodeSection = AllocatePool (sizeof (*ImageRecordCodeSection));
- if (ImageRecordCodeSection == NULL) {
- return;
- }
-
- ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
-
- ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
- ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE (Section[Index].SizeOfRawData, SectionAlignment);
-
- DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
-
- InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
- ImageRecord->CodeSegmentCount++;
- }
- }
-
- if (ImageRecord->CodeSegmentCount == 0) {
- //
- // If a UEFI executable consists of a single read+write+exec PE/COFF
- // section, that isn't actually an error. The image can be launched
- // alright, only image protection cannot be applied to it fully.
- //
- // One example that elicits this is (some) Linux kernels (with the EFI stub
- // of course).
- //
- DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageAddress);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
- }
-
- goto Finish;
- }
+ Status = CreateImagePropertiesRecord (
+ LoadedImage->ImageBase,
+ LoadedImage->ImageSize,
+ &RequiredAlignment,
+ ImageRecord
+ );
- //
- // Final
- //
- SortImageRecordCodeSection (ImageRecord);
- //
- // Check overlap all section in ImageBase/Size
- //
- if (!IsImageRecordCodeSectionValid (ImageRecord)) {
- DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a failed to create image properties record\n", __func__));
+ FreePool (ImageRecord);
goto Finish;
}
//
- // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
- // Given that the loader always allocates full pages, we know the space after the image is not used.
- //
- ImageRecord->ImageSize = ALIGN_VALUE (LoadedImage->ImageSize, EFI_PAGE_SIZE);
-
- //
// CPU ARCH present. Update memory attribute directly.
//
SetUefiImageProtectionAttributes (ImageRecord);
@@ -607,7 +422,7 @@ UnprotectUefiImage (
ImageRecord->ImageSize,
0
);
- FreeImageRecord (ImageRecord);
+ DeleteImagePropertiesRecord (ImageRecord);
return;
}
}