/** @file Locate, get and update PE/COFF permissions during Standalone MM Foundation Entry point on ARM platforms. Copyright (c) 2017 - 2018, ARM Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include EFI_STATUS EFIAPI UpdateMmFoundationPeCoffPermissions ( IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN UINT32 SectionHeaderOffset, IN CONST UINT16 NumberOfSections, IN REGION_PERMISSION_UPDATE_FUNC TextUpdater, IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater, IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater ) { EFI_IMAGE_SECTION_HEADER SectionHeader; RETURN_STATUS Status; EFI_PHYSICAL_ADDRESS Base; UINTN Size; UINTN ReadSize; UINTN Index; ASSERT (ImageContext != NULL); // // Iterate over the sections // for (Index = 0; Index < NumberOfSections; Index++) { // // Read section header from file // Size = sizeof (EFI_IMAGE_SECTION_HEADER); ReadSize = Size; Status = ImageContext->ImageRead ( ImageContext->Handle, SectionHeaderOffset, &Size, &SectionHeader ); if (RETURN_ERROR (Status) || (Size != ReadSize)) { DEBUG ((DEBUG_ERROR, "%a: ImageContext->ImageRead () failed (Status = %r)\n", __FUNCTION__, Status)); return Status; } DEBUG ((DEBUG_INFO, "%a: Section %d of image at 0x%lx has 0x%x permissions\n", __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics)); DEBUG ((DEBUG_INFO, "%a: Section %d of image at 0x%lx has %a name\n", __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Name)); DEBUG ((DEBUG_INFO, "%a: Section %d of image at 0x%lx has 0x%x address\n", __FUNCTION__, Index, ImageContext->ImageAddress, ImageContext->ImageAddress + SectionHeader.VirtualAddress)); DEBUG ((DEBUG_INFO, "%a: Section %d of image at 0x%lx has 0x%x data\n", __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.PointerToRawData)); // // If the section is marked as XN then remove the X attribute. Furthermore, // if it is a writeable section then mark it appropriately as well. // if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { Base = ImageContext->ImageAddress + SectionHeader.VirtualAddress; TextUpdater (Base, SectionHeader.Misc.VirtualSize); if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) { ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize); DEBUG ((DEBUG_INFO, "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n", __FUNCTION__, Index, ImageContext->ImageAddress)); } else { DEBUG ((DEBUG_INFO, "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n", __FUNCTION__, Index, ImageContext->ImageAddress)); } } else { DEBUG ((DEBUG_INFO, "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n", __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics)); } SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); } return RETURN_SUCCESS; } EFI_STATUS EFIAPI LocateStandaloneMmCorePeCoffData ( IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress, IN OUT VOID **TeData, IN OUT UINTN *TeDataSize ) { EFI_FFS_FILE_HEADER *FileHeader = NULL; EFI_STATUS Status; Status = FfsFindNextFile ( EFI_FV_FILETYPE_SECURITY_CORE, BfvAddress, &FileHeader ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM FFS file - 0x%x\n", Status)); return Status; } Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, TeData, TeDataSize); if (EFI_ERROR (Status)) { Status = FfsFindSectionData (EFI_SECTION_TE, FileHeader, TeData, TeDataSize); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Section data - %r\n", Status)); return Status; } } DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData)); return Status; } STATIC EFI_STATUS GetPeCoffSectionInformation ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, OUT UINT32 *SectionHeaderOffset, OUT UINT16 *NumberOfSections ) { RETURN_STATUS Status; EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; UINTN Size; UINTN ReadSize; ASSERT (ImageContext != NULL); ASSERT (SectionHeaderOffset != NULL); ASSERT (NumberOfSections != NULL); Status = PeCoffLoaderGetImageInfo (ImageContext); if (RETURN_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n", __FUNCTION__, Status)); return Status; } if (ImageContext->SectionAlignment < EFI_PAGE_SIZE) { // // The sections need to be at least 4 KB aligned, since that is the // granularity at which we can tighten permissions. // if (!ImageContext->IsTeImage) { DEBUG ((DEBUG_WARN, "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n", __FUNCTION__, ImageContext->ImageAddress, ImageContext->SectionAlignment)); return RETURN_UNSUPPORTED; } ImageContext->SectionAlignment = EFI_PAGE_SIZE; } // // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic // determines if this is a PE32 or PE32+ image. The magic is in the same // location in both images. // Hdr.Union = &HdrData; Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); ReadSize = Size; Status = ImageContext->ImageRead ( ImageContext->Handle, ImageContext->PeCoffHeaderOffset, &Size, Hdr.Pe32 ); if (RETURN_ERROR (Status) || (Size != ReadSize)) { DEBUG ((DEBUG_ERROR, "%a: TmpContext->ImageRead () failed (Status = %r)\n", __FUNCTION__, Status)); return Status; } if (!ImageContext->IsTeImage) { ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE); *SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER); *NumberOfSections = Hdr.Pe32->FileHeader.NumberOfSections; switch (Hdr.Pe32->OptionalHeader.Magic) { case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: *SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader; break; case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: *SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader; break; default: ASSERT (FALSE); } } else { *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER)); *NumberOfSections = Hdr.Te->NumberOfSections; ImageContext->ImageAddress -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } return RETURN_SUCCESS; } EFI_STATUS EFIAPI GetStandaloneMmCorePeCoffSections ( IN VOID *TeData, IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN OUT UINT32 *SectionHeaderOffset, IN OUT UINT16 *NumberOfSections ) { EFI_STATUS Status; // Initialize the Image Context ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); ImageContext->Handle = TeData; ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory; DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData)); Status = GetPeCoffSectionInformation (ImageContext, SectionHeaderOffset, NumberOfSections); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status)); return Status; } DEBUG ((DEBUG_INFO, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n", *SectionHeaderOffset, *NumberOfSections)); return Status; }