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,160 +360,21 @@ ProtectUefiImage ( return; } - ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE; + RequiredAlignment = GetMemoryProtectionSectionAlignment (LoadedImage->ImageCodeType); - // - // Step 1: record whole region - // - ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase; - ImageRecord->ImageSize = LoadedImage->ImageSize; + Status = CreateImagePropertiesRecord ( + LoadedImage->ImageBase, + LoadedImage->ImageSize, + &RequiredAlignment, + ImageRecord + ); - 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; - } - - 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. + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a failed to create image properties record\n", __func__)); + FreePool (ImageRecord); 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; - } - - // - // Final - // - SortImageRecordCodeSection (ImageRecord); - // - // Check overlap all section in ImageBase/Size - // - if (!IsImageRecordCodeSectionValid (ImageRecord)) { - DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n")); - 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. // @@ -607,7 +422,7 @@ UnprotectUefiImage ( ImageRecord->ImageSize, 0 ); - FreeImageRecord (ImageRecord); + DeleteImagePropertiesRecord (ImageRecord); return; } }