From: "Oliver Smith-Denny" <osde@linux.microsoft.com>
To: devel@edk2.groups.io, ardb@kernel.org
Cc: Ray Ni <ray.ni@intel.com>, Jiewen Yao <jiewen.yao@intel.com>,
Gerd Hoffmann <kraxel@redhat.com>,
Taylor Beebe <t@taylorbeebe.com>,
Oliver Smith-Denny <osd@smith-denny.com>,
Dandan Bi <dandan.bi@intel.com>,
Liming Gao <gaoliming@byosoft.com.cn>,
"Kinney, Michael D" <michael.d.kinney@intel.com>,
Leif Lindholm <quic_llindhol@quicinc.com>,
Sunil V L <sunilvl@ventanamicro.com>,
Andrei Warkentin <andrei.warkentin@intel.com>
Subject: Re: [edk2-devel] [RFC PATCH 07/10] MdeModulePkg/PeiCore: Apply restricted permissions in image loader
Date: Thu, 25 May 2023 10:21:34 -0700 [thread overview]
Message-ID: <dbe7a641-783a-012b-82d2-2a71b10b53f7@linux.microsoft.com> (raw)
In-Reply-To: <20230525143041.1172989-8-ardb@kernel.org>
On 5/25/2023 7:30 AM, Ard Biesheuvel wrote:
> Add a notification callback to the PEI core to grab a reference to the
> memory attributes PPI as soon as it is registered, and use it in the
> image loader to set restricted memory permissions after loading the
> image if the image was loaded into memory.
>
> There are two use cases for this:
> - when the DXE IPL loads the DXE core using the PEI image services, its
> mappings will be set according to the PE section permission attributes
> if the image was built with 4k section alignment; this means DXE core
> will never run with mappings that are both writable and executable.
> - when PEIMs are shadowed to memory, they will not only be mapped
> read-only, but any non-exec permissions will also be removed. (Note
> that this requires the component that installs PEI permanent memory to
> depex on the memory attributes PPI, to ensure that it is available to
> manage permissions on permanent memory before it is used to load
> images)
>
> With this logic in place *, there is no longer a need for system memory
> to be mapped with both write and execute permissions out of reset.
> Instead, all memory can be mapped with non-executable permissions by
> default, which means that the stack and other allocations used in PEI or
> early in DXE will no longer need to be mapped non-exec explicitly.
>
> * the DXE core will also need its own method for clearing non-exec
> permissions on memory ranges, but this is being addressed in a
> separate series.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> MdeModulePkg/Core/Pei/Image/Image.c | 160 ++++++++++++++++++++
> MdeModulePkg/Core/Pei/PeiMain.h | 6 +
> MdeModulePkg/Core/Pei/PeiMain.inf | 1 +
> 3 files changed, 167 insertions(+)
>
> diff --git a/MdeModulePkg/Core/Pei/Image/Image.c b/MdeModulePkg/Core/Pei/Image/Image.c
> index cee9f09c6ea61e31..3a7de45014b8f772 100644
> --- a/MdeModulePkg/Core/Pei/Image/Image.c
> +++ b/MdeModulePkg/Core/Pei/Image/Image.c
> @@ -18,6 +18,50 @@ EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
> &mPeiLoadImagePpi
>
> };
>
>
>
> +/**
>
> + Provide a callback for when the memory attributes PPI is installed.
>
> +
>
> + @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table
>
> + published by the PEI Foundation.
>
> + @param NotifyDescriptor The descriptor for the notification event.
>
> + @param Ppi Pointer to the PPI in question.
>
> +
>
> + @return Always success
>
> +
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +EFIAPI
>
> +MemoryAttributePpiNotifyCallback (
>
> + IN EFI_PEI_SERVICES **PeiServices,
>
> + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
>
> + IN VOID *Ppi
>
> + )
>
> +{
>
> + PEI_CORE_INSTANCE *PrivateData;
>
> +
>
> + //
>
> + // Get PEI Core private data
>
> + //
>
> + PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
>
> +
>
> + //
>
> + // If there isn't a memory attribute PPI installed, use the one from
>
> + // notification
>
> + //
>
> + if (PrivateData->MemoryAttributePpi == NULL) {
>
> + PrivateData->MemoryAttributePpi = (EDKII_MEMORY_ATTRIBUTE_PPI *)Ppi;
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
>
> + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
>
> + &gEdkiiMemoryAttributePpiGuid,
>
> + MemoryAttributePpiNotifyCallback
>
> +};
>
> +
>
> /**
>
>
>
> Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
>
> @@ -243,6 +287,106 @@ GetPeCoffImageFixLoadingAssignedAddress (
> return Status;
>
> }
>
>
>
> +/**
>
> + Remap the memory region covering a loaded image so it can be executed.
>
> +
>
> + @param ImageContext Pointer to the image context structure that describes the
>
> + PE/COFF image that needs to be examined by this function.
>
> + @param FileType The FFS file type of the image
>
> + @param ImageAddress The start of the memory region covering the image
>
> + @param ImageSize The size of the memory region covering the image
>
> +
>
> + @retval EFI_SUCCESS The image is ready to be executed
>
> + @retval EFI_OUT_OF_RESOURCES Not enough memory available to update the memory
>
> + mapping
>
> +
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +RemapLoadedImageForExecution (
>
> + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
>
> + IN EFI_FV_FILETYPE FileType,
>
> + IN PHYSICAL_ADDRESS ImageAddress,
>
> + IN UINT64 ImageSize
>
> + )
>
> +{
>
> + PEI_CORE_INSTANCE *Private;
>
> + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
>
> + EFI_IMAGE_SECTION_HEADER *Section;
>
> + PHYSICAL_ADDRESS SectionAddress;
>
> + EFI_STATUS Status;
>
> + UINT64 Permissions;
>
> + UINTN Index;
>
> +
>
> + Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
>
> +
>
> + if (Private->MemoryAttributePpi == NULL) {
>
> + return EFI_SUCCESS;
We will have a gap here before the MemoryAttributePpi is installed,
obviously, when CpuPei is installed. Is the expectation that only
dependencies for CpuPei will be launched before and everything else
will have a dependency on CpuPei?
Or, is it that shadowed PEIMs won't happen before CpuPei? I am curious
how big or small of a gap this really is.
>
> + }
>
> +
>
> + //
>
> + // PEI phase executables must be able to execute in place from read-only NOR
>
> + // flash, and so they can be mapped read-only in their entirety.
>
> + //
>
> + if ((FileType == EFI_FV_FILETYPE_PEI_CORE) ||
>
> + (FileType == EFI_FV_FILETYPE_PEIM) ||
>
> + (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))
>
> + {
We are calling this from PEI Core, will we have more images of type
PEI Core? I understand if this is for completeness, but just making
sure I understand the flow.
Thanks,
Oliver
>
> + return Private->MemoryAttributePpi->SetPermissions (
>
> + Private->MemoryAttributePpi,
>
> + ImageAddress,
>
> + ImageSize,
>
> + EFI_MEMORY_RO,
>
> + EFI_MEMORY_XP
>
> + );
>
> + }
>
> +
>
> + //
>
> + // Only PE images with minimum 4k section alignment can be remapped with
>
> + // restricted permissions.
>
> + //
>
> + if (ImageContext->IsTeImage ||
>
> + (ImageContext->SectionAlignment < EFI_PAGE_SIZE))
>
> + {
>
> + return EFI_UNSUPPORTED;
>
> + }
>
> +
>
> + Hdr.Union = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINT8 *)ImageContext->Handle +
>
> + ImageContext->PeCoffHeaderOffset);
>
> + ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
>
> +
>
> + Section = (EFI_IMAGE_SECTION_HEADER *)((UINT8 *)Hdr.Union + sizeof (UINT32) +
>
> + sizeof (EFI_IMAGE_FILE_HEADER) +
>
> + Hdr.Pe32->FileHeader.SizeOfOptionalHeader
>
> + );
>
> +
>
> + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
>
> + SectionAddress = ImageContext->ImageAddress + Section[Index].VirtualAddress;
>
> + Permissions = 0;
>
> +
>
> + if ((Section[Index].Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0) {
>
> + Permissions |= EFI_MEMORY_RO;
>
> + }
>
> +
>
> + if ((Section[Index].Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
>
> + Permissions |= EFI_MEMORY_XP;
>
> + }
>
> +
>
> + Status = Private->MemoryAttributePpi->SetPermissions (
>
> + Private->MemoryAttributePpi,
>
> + SectionAddress,
>
> + Section[Index].Misc.VirtualSize,
>
> + Permissions,
>
> + Permissions ^ EFI_MEMORY_RO ^ EFI_MEMORY_XP
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> /**
>
>
>
> Loads and relocates a PE/COFF image into memory.
>
> @@ -456,9 +600,24 @@ LoadAndRelocatePeCoffImage (
>
>
> //
>
> // Flush the instruction cache so the image data is written before we execute it
>
> + // Also ensure that the pages are mapped for execution
>
> //
>
> if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
>
> InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
>
> +
>
> + Status = RemapLoadedImageForExecution (
>
> + &ImageContext,
>
> + FileInfo.FileType,
>
> + ImageContext.ImageAddress & ~(UINT64)EFI_PAGE_MASK,
>
> + ALIGN_VALUE (
>
> + AlignImageSize + (ImageContext.ImageAddress & EFI_PAGE_MASK),
>
> + EFI_PAGE_SIZE
>
> + )
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + ASSERT_EFI_ERROR (Status);
>
> + return Status;
>
> + }
>
> }
>
>
>
> *ImageAddress = ImageContext.ImageAddress;
>
> @@ -972,6 +1131,7 @@ InitializeImageServices (
> //
>
> PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
>
> PeiServicesInstallPpi (PrivateData->XipLoadFile);
>
> + PeiServicesNotifyPpi (&mNotifyList);
>
> } else {
>
> //
>
> // 2nd time we are running from memory so replace the XIP version with the
>
> diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h
> index 556beddad533989f..5499d53b0bbaf641 100644
> --- a/MdeModulePkg/Core/Pei/PeiMain.h
> +++ b/MdeModulePkg/Core/Pei/PeiMain.h
> @@ -26,6 +26,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> #include <Ppi/TemporaryRamDone.h>
>
> #include <Ppi/SecHobData.h>
>
> #include <Ppi/PeiCoreFvLocation.h>
>
> +#include <Ppi/MemoryAttribute.h>
>
> #include <Library/DebugLib.h>
>
> #include <Library/PeiCoreEntryPoint.h>
>
> #include <Library/BaseLib.h>
>
> @@ -302,6 +303,11 @@ struct _PEI_CORE_INSTANCE {
> //
>
> EFI_GUID *TempFileGuid;
>
>
>
> + //
>
> + // Pointer to the memory attribute PPI
>
> + //
>
> + EDKII_MEMORY_ATTRIBUTE_PPI *MemoryAttributePpi;
>
> +
>
> //
>
> // Temp Memory Range is not covered by PeiTempMem and Stack.
>
> // Those Memory Range will be migrated into physical memory.
>
> diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf
> index 0cf357371a16d872..55d8eb3e862d6418 100644
> --- a/MdeModulePkg/Core/Pei/PeiMain.inf
> +++ b/MdeModulePkg/Core/Pei/PeiMain.inf
> @@ -100,6 +100,7 @@ [Ppis]
> gEfiPeiReset2PpiGuid ## SOMETIMES_CONSUMES
>
> gEfiSecHobDataPpiGuid ## SOMETIMES_CONSUMES
>
> gEfiPeiCoreFvLocationPpiGuid ## SOMETIMES_CONSUMES
>
> + gEdkiiMemoryAttributePpiGuid ## SOMETIMES_CONSUMES
>
>
>
> [Pcd]
>
> gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES
>
next prev parent reply other threads:[~2023-05-25 17:21 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-25 14:30 [RFC PATCH 00/10] Add PPI to manage PEI phase memory attributes Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 01/10] ArmPkg/ArmMmuLib: Extend API to manage memory permissions better Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 02/10] ArmPkg/CpuDxe: Simplify memory attributes protocol implementation Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 03/10] ArmPkg/CpuPei: Drop bogus DEPEX on PEI permanent memory Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 04/10] OvmfPkg/RiscVVirt: Remove unimplemented NxForStack configuration Ard Biesheuvel
2023-05-29 12:50 ` Sunil V L
2023-05-25 14:30 ` [RFC PATCH 05/10] MdeModulePkg: Define memory attribute PPI Ard Biesheuvel
2023-05-30 7:15 ` Ni, Ray
2023-05-30 7:32 ` Ard Biesheuvel
2023-05-31 7:33 ` Ni, Ray
2023-05-31 7:53 ` Ard Biesheuvel
2023-05-31 8:56 ` [edk2-devel] " Ni, Ray
2023-05-31 9:24 ` Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 06/10] ArmPkg/CpuPei: Implement the memory attributes PPI Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 07/10] MdeModulePkg/PeiCore: Apply restricted permissions in image loader Ard Biesheuvel
2023-05-25 17:21 ` Oliver Smith-Denny [this message]
2023-05-25 21:29 ` [edk2-devel] " Ard Biesheuvel
2023-05-30 16:51 ` Oliver Smith-Denny
2023-05-30 20:51 ` Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 08/10] MdeModulePkg/DxeIpl: Merge EBC, RISCV64 and LOONGARCH code Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 09/10] MdeModulePkg/DxeIpl: Use memory attribute PPI to remap the stack NX Ard Biesheuvel
2023-05-30 7:19 ` Ni, Ray
2023-05-30 10:25 ` duntan
2023-05-30 12:51 ` Ard Biesheuvel
2023-05-31 7:22 ` Gerd Hoffmann
2023-05-31 1:29 ` Ni, Ray
2023-05-31 19:03 ` [edk2-devel] " Lendacky, Thomas
2023-05-31 21:01 ` Ard Biesheuvel
2023-05-25 14:30 ` [RFC PATCH 10/10] MdeModulePkg/DxeIpl ARM AARCH64: Switch to generic handoff code Ard Biesheuvel
2023-05-25 17:20 ` [edk2-devel] [RFC PATCH 00/10] Add PPI to manage PEI phase memory attributes Oliver Smith-Denny
2023-05-25 21:43 ` Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=dbe7a641-783a-012b-82d2-2a71b10b53f7@linux.microsoft.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox