From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=217.140.101.70; helo=foss.arm.com; envelope-from=sughosh.ganu@arm.com; receiver=edk2-devel@lists.01.org Received: from foss.arm.com (foss.arm.com [217.140.101.70]) by ml01.01.org (Postfix) with ESMTP id AABD921B02822 for ; Mon, 26 Nov 2018 22:23:17 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 804352379; Mon, 26 Nov 2018 22:23:17 -0800 (PST) Received: from usa.arm.com (a074948-lin.blr.arm.com [10.162.4.56]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 3B4483F5AF; Mon, 26 Nov 2018 22:23:15 -0800 (PST) From: Sughosh Ganu To: edk2-devel@lists.01.org, Achin Gupta Date: Tue, 27 Nov 2018 11:52:55 +0530 Message-Id: <1543299775-25345-3-git-send-email-sughosh.ganu@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1543299775-25345-1-git-send-email-sughosh.ganu@arm.com> References: <1543299775-25345-1-git-send-email-sughosh.ganu@arm.com> Subject: [PATCH v2 2/2] StandaloneMM: Update permissions for Standalone MM drivers memory area X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Nov 2018 06:23:17 -0000 X-List-Received-Date: Tue, 27 Nov 2018 06:23:17 -0000 X-List-Received-Date: Tue, 27 Nov 2018 06:23:17 -0000 X-List-Received-Date: Tue, 27 Nov 2018 06:23:17 -0000 X-List-Received-Date: Tue, 27 Nov 2018 06:23:17 -0000 The StandaloneMM image executes in S-EL0 on reference Arm platforms and is deployed by the trusted firmware as BL32 image. Memory for the Standalone MM drivers is marked as RW+XN initially, allowing the drivers to be loaded into the memory. Once loaded, the memory attributes need to be changed to RO+XN for rodata sections and RO+X for code sections. Achieve this through the extra action 'UpdatePeCoffPermissions' to request the privileged firmware in EL3 to update the permissions. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Sughosh Ganu --- .../StandaloneMmPeCoffExtraActionLib.inf | 18 +- .../StandaloneMmPeCoffExtraActionLib.c | 222 +++++++++++++++++++++ 2 files changed, 233 insertions(+), 7 deletions(-) copy ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf => StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf (72%) create mode 100644 StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.c diff --git a/ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf b/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf similarity index 72% copy from ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf copy to StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf index 3be0237a3689..87734f69b75d 100644 --- a/ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf +++ b/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf @@ -16,9 +16,9 @@ #**/ [Defines] - INF_VERSION = 0x00010005 - BASE_NAME = RvdUnixPeCoffExtraActionLib - FILE_GUID = 5EDEB7E7-EA55-4E92-8216-335AC98A3B11 + INF_VERSION = 0x0001000A + BASE_NAME = StandaloneMmPeCoffExtraActionLib + FILE_GUID = 8B40543B-9588-48F8-840C-5A60E6DB1B03 MODULE_TYPE = BASE VERSION_STRING = 1.0 LIBRARY_CLASS = PeCoffExtraActionLib @@ -30,12 +30,16 @@ [Defines] # [Sources.common] - RvdPeCoffExtraActionLib.c + StandaloneMmPeCoffExtraActionLib.c [Packages] - MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[FeaturePcd] + gStandaloneMmPkgTokenSpaceGuid.PcdStandaloneMmEnable [LibraryClasses] - DebugLib - SemihostLib + StandaloneMmMmuLib + PcdLib diff --git a/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.c b/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.c new file mode 100644 index 000000000000..1c9fec201916 --- /dev/null +++ b/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.c @@ -0,0 +1,222 @@ +/**@file + +Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+Portions copyright (c) 2011 - 2018, ARM Ltd. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +STATIC +RETURN_STATUS +UpdatePeCoffPermissions ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN REGION_PERMISSION_UPDATE_FUNC NoExecUpdater, + IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + UINTN Size; + UINTN ReadSize; + UINT32 SectionHeaderOffset; + UINTN NumberOfSections; + UINTN Index; + EFI_IMAGE_SECTION_HEADER SectionHeader; + PE_COFF_LOADER_IMAGE_CONTEXT TmpContext; + EFI_PHYSICAL_ADDRESS Base; + + // + // We need to copy ImageContext since PeCoffLoaderGetImageInfo () + // will mangle the ImageAddress field + // + CopyMem (&TmpContext, ImageContext, sizeof (TmpContext)); + + if (TmpContext.PeCoffHeaderOffset == 0) { + Status = PeCoffLoaderGetImageInfo (&TmpContext); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + } + + if (TmpContext.IsTeImage && + TmpContext.ImageAddress == ImageContext->ImageAddress) { + DEBUG ((DEBUG_INFO, "%a: ignoring XIP TE image at 0x%lx\n", __FUNCTION__, + ImageContext->ImageAddress)); + return RETURN_SUCCESS; + } + + if (TmpContext.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. So just clear the + // noexec permissions on the entire region. + // + if (!TmpContext.IsTeImage) { + DEBUG ((DEBUG_WARN, + "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n", + __FUNCTION__, ImageContext->ImageAddress, TmpContext.SectionAlignment)); + } + Base = ImageContext->ImageAddress & ~(EFI_PAGE_SIZE - 1); + Size = ImageContext->ImageAddress - Base + ImageContext->ImageSize; + return NoExecUpdater (Base, ALIGN_VALUE (Size, 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 = TmpContext.ImageRead (TmpContext.Handle, + TmpContext.PeCoffHeaderOffset, &Size, Hdr.Pe32); + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((DEBUG_ERROR, + "%a: TmpContext.ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE); + + SectionHeaderOffset = TmpContext.PeCoffHeaderOffset + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER); + NumberOfSections = (UINTN)(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); + } + + // + // Iterate over the sections + // + for (Index = 0; Index < NumberOfSections; Index++) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + ReadSize = Size; + Status = TmpContext.ImageRead (TmpContext.Handle, SectionHeaderOffset, + &Size, &SectionHeader); + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((DEBUG_ERROR, + "%a: TmpContext.ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + Base = TmpContext.ImageAddress + SectionHeader.VirtualAddress; + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0 && + TmpContext.ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + + DEBUG ((DEBUG_INFO, + "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n", + __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize)); + ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize); + } else { + DEBUG ((DEBUG_WARN, + "%a: Mapping section %d of image at 0x%lx with RW-XN permissions and size 0x%x\n", + __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize)); + } + } else { + DEBUG ((DEBUG_INFO, + "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n", + __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize)); + ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize); + + DEBUG ((DEBUG_INFO, + "%a: Mapping section %d of image at 0x%lx with RO-X permissions and size 0x%x\n", + __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize)); + NoExecUpdater (Base, SectionHeader.Misc.VirtualSize); + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + return RETURN_SUCCESS; +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +PeCoffLoaderRelocateImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UpdatePeCoffPermissions ( + ImageContext, + ArmClearMemoryRegionNoExec, + ArmSetMemoryRegionReadOnly + ); +} + + + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +PeCoffLoaderUnloadImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UpdatePeCoffPermissions ( + ImageContext, + ArmSetMemoryRegionNoExec, + ArmClearMemoryRegionReadOnly + ); +} -- 2.7.4