StandaloneMM: Update permissions for Standalone MM drivers memory area

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 <sughosh.ganu@arm.com>
Reviewed-by: Achin Gupta <achin.gupta@arm.com>
This commit is contained in:
Sughosh Ganu 2018-12-03 12:49:02 +05:30 committed by Achin Gupta
parent 34b1d7eafe
commit f7f94ffe88
2 changed files with 267 additions and 0 deletions

View File

@ -0,0 +1,222 @@
/**@file
Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
Portions copyright (c) 2011 - 2018, ARM Ltd. All rights reserved.<BR>
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 <PiDxe.h>
#include <Library/ArmMmuLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/PeCoffLib.h>
#include <Library/PeCoffExtraActionLib.h>
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
);
}

View File

@ -0,0 +1,45 @@
#/** @file
# PeCoff extra action libary for DXE phase that run Unix emulator.
#
# Lib to provide memory journal status code reporting Routines
# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
# Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
# 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.
#
#
#**/
[Defines]
INF_VERSION = 0x0001000A
BASE_NAME = StandaloneMmPeCoffExtraActionLib
FILE_GUID = 8B40543B-9588-48F8-840C-5A60E6DB1B03
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = PeCoffExtraActionLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = ARM
#
[Sources.common]
AArch64/StandaloneMmPeCoffExtraActionLib.c
[Packages]
ArmPkg/ArmPkg.dec
MdePkg/MdePkg.dec
StandaloneMmPkg/StandaloneMmPkg.dec
[FeaturePcd]
gStandaloneMmPkgTokenSpaceGuid.PcdStandaloneMmEnable
[LibraryClasses]
StandaloneMmMmuLib
PcdLib