From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by mx.groups.io with SMTP id smtpd.web11.13286.1685025080172823124 for ; Thu, 25 May 2023 07:31:20 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=mP+hUJfF; spf=pass (domain: kernel.org, ip: 139.178.84.217, mailfrom: ardb@kernel.org) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id A620064629; Thu, 25 May 2023 14:31:19 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8CC95C433EF; Thu, 25 May 2023 14:31:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1685025079; bh=HTbMDRRDhdHA04mt2zJatFS+ZfEQxazVHmqPbj810BA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mP+hUJfFSFl2++H7XK/HqwzUasFKEU18oyNRJjsET21mHZp4mOI8Cx3flJDlzhHoy lHLCjl9chZhWH/PAL1hY1jmMiaHaUlVt3243cym58z8zt+IBLZCROea8/A5Y83qEpj zrnae5+Koa+/yaySIcodvOqUGa0Zil/fYffhhZmMqkHk2zV7ZlcPVncp9OipTRYB6+ lZqiwnUP3fVcn+i38H1I+085C6SoH/1+OTPlP9A7sSCOq+z4nfNjhbqPyTTb7W5DDL yB2MEG/LIcHZoiZ+6bN8qzjL6EtRq0QnrAOXuXpbjwW+Ti5dB9ZSLn2uRvQ4+OUtqr c/XjGHF7XJAlg== From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: Ard Biesheuvel , Ray Ni , Jiewen Yao , Gerd Hoffmann , Taylor Beebe , Oliver Smith-Denny , Dandan Bi , Liming Gao , "Kinney, Michael D" , Leif Lindholm , Sunil V L , Andrei Warkentin Subject: [RFC PATCH 07/10] MdeModulePkg/PeiCore: Apply restricted permissions in image loader Date: Thu, 25 May 2023 16:30:38 +0200 Message-Id: <20230525143041.1172989-8-ardb@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230525143041.1172989-1-ardb@kernel.org> References: <20230525143041.1172989-1-ardb@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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 --- 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/Im= age/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 =3D { &mPeiLoadImagePpi=0D };=0D =0D +/**=0D + Provide a callback for when the memory attributes PPI is installed.=0D +=0D + @param PeiServices An indirect pointer to the EFI_PEI_SERVICES ta= ble=0D + published by the PEI Foundation.=0D + @param NotifyDescriptor The descriptor for the notification event.=0D + @param Ppi Pointer to the PPI in question.=0D +=0D + @return Always success=0D +=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +EFIAPI=0D +MemoryAttributePpiNotifyCallback (=0D + IN EFI_PEI_SERVICES **PeiServices,=0D + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,=0D + IN VOID *Ppi=0D + )=0D +{=0D + PEI_CORE_INSTANCE *PrivateData;=0D +=0D + //=0D + // Get PEI Core private data=0D + //=0D + PrivateData =3D PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);=0D +=0D + //=0D + // If there isn't a memory attribute PPI installed, use the one from=0D + // notification=0D + //=0D + if (PrivateData->MemoryAttributePpi =3D=3D NULL) {=0D + PrivateData->MemoryAttributePpi =3D (EDKII_MEMORY_ATTRIBUTE_PPI *)Ppi;= =0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList =3D {=0D + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINAT= E_LIST,=0D + &gEdkiiMemoryAttributePpiGuid,=0D + MemoryAttributePpiNotifyCallback=0D +};=0D +=0D /**=0D =0D Support routine for the PE/COFF Loader that reads a buffer from a PE/COF= F file.=0D @@ -243,6 +287,106 @@ GetPeCoffImageFixLoadingAssignedAddress ( return Status;=0D }=0D =0D +/**=0D + Remap the memory region covering a loaded image so it can be executed.=0D +=0D + @param ImageContext Pointer to the image context structure that descr= ibes the=0D + PE/COFF image that needs to be examined by this f= unction.=0D + @param FileType The FFS file type of the image=0D + @param ImageAddress The start of the memory region covering the image= =0D + @param ImageSize The size of the memory region covering the image= =0D +=0D + @retval EFI_SUCCESS The image is ready to be executed=0D + @retval EFI_OUT_OF_RESOURCES Not enough memory available to update the = memory=0D + mapping=0D +=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +RemapLoadedImageForExecution (=0D + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,=0D + IN EFI_FV_FILETYPE FileType,=0D + IN PHYSICAL_ADDRESS ImageAddress,=0D + IN UINT64 ImageSize=0D + )=0D +{=0D + PEI_CORE_INSTANCE *Private;=0D + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;=0D + EFI_IMAGE_SECTION_HEADER *Section;=0D + PHYSICAL_ADDRESS SectionAddress;=0D + EFI_STATUS Status;=0D + UINT64 Permissions;=0D + UINTN Index;=0D +=0D + Private =3D PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer (= ));=0D +=0D + if (Private->MemoryAttributePpi =3D=3D NULL) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + //=0D + // PEI phase executables must be able to execute in place from read-only= NOR=0D + // flash, and so they can be mapped read-only in their entirety.=0D + //=0D + if ((FileType =3D=3D EFI_FV_FILETYPE_PEI_CORE) ||=0D + (FileType =3D=3D EFI_FV_FILETYPE_PEIM) ||=0D + (FileType =3D=3D EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))=0D + {=0D + return Private->MemoryAttributePpi->SetPermissions (=0D + Private->MemoryAttributePpi,=0D + ImageAddress,=0D + ImageSize,=0D + EFI_MEMORY_RO,=0D + EFI_MEMORY_XP=0D + );=0D + }=0D +=0D + //=0D + // Only PE images with minimum 4k section alignment can be remapped with= =0D + // restricted permissions.=0D + //=0D + if (ImageContext->IsTeImage ||=0D + (ImageContext->SectionAlignment < EFI_PAGE_SIZE))=0D + {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + Hdr.Union =3D (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINT8 *)ImageContext-= >Handle +=0D + ImageContext->PeCoffHead= erOffset);=0D + ASSERT (Hdr.Pe32->Signature =3D=3D EFI_IMAGE_NT_SIGNATURE);=0D +=0D + Section =3D (EFI_IMAGE_SECTION_HEADER *)((UINT8 *)Hdr.Union + sizeof (UI= NT32) +=0D + sizeof (EFI_IMAGE_FILE_HEADER) += =0D + Hdr.Pe32->FileHeader.SizeOfOption= alHeader=0D + );=0D +=0D + for (Index =3D 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++= ) {=0D + SectionAddress =3D ImageContext->ImageAddress + Section[Index].Virtual= Address;=0D + Permissions =3D 0;=0D +=0D + if ((Section[Index].Characteristics & EFI_IMAGE_SCN_MEM_WRITE) =3D=3D = 0) {=0D + Permissions |=3D EFI_MEMORY_RO;=0D + }=0D +=0D + if ((Section[Index].Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) =3D= =3D 0) {=0D + Permissions |=3D EFI_MEMORY_XP;=0D + }=0D +=0D + Status =3D Private->MemoryAttributePpi->SetPermissions (=0D + Private->MemoryAttributePpi,=0D + SectionAddress,=0D + Section[Index].Misc.VirtualSiz= e,=0D + Permissions,=0D + Permissions ^ EFI_MEMORY_RO ^ = EFI_MEMORY_XP=0D + );=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D /**=0D =0D Loads and relocates a PE/COFF image into memory.=0D @@ -456,9 +600,24 @@ LoadAndRelocatePeCoffImage ( =0D //=0D // Flush the instruction cache so the image data is written before we ex= ecute it=0D + // Also ensure that the pages are mapped for execution=0D //=0D if (ImageContext.ImageAddress !=3D (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data= ) {=0D InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddr= ess, (UINTN)ImageContext.ImageSize);=0D +=0D + Status =3D RemapLoadedImageForExecution (=0D + &ImageContext,=0D + FileInfo.FileType,=0D + ImageContext.ImageAddress & ~(UINT64)EFI_PAGE_MASK,=0D + ALIGN_VALUE (=0D + AlignImageSize + (ImageContext.ImageAddress & EFI_PAGE_MA= SK),=0D + EFI_PAGE_SIZE=0D + )=0D + );=0D + if (EFI_ERROR (Status)) {=0D + ASSERT_EFI_ERROR (Status);=0D + return Status;=0D + }=0D }=0D =0D *ImageAddress =3D ImageContext.ImageAddress;=0D @@ -972,6 +1131,7 @@ InitializeImageServices ( //=0D PrivateData->XipLoadFile =3D &gPpiLoadFilePpiList;=0D PeiServicesInstallPpi (PrivateData->XipLoadFile);=0D + PeiServicesNotifyPpi (&mNotifyList);=0D } else {=0D //=0D // 2nd time we are running from memory so replace the XIP version with= the=0D diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMai= n.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 =0D #include =0D #include =0D +#include =0D #include =0D #include =0D #include =0D @@ -302,6 +303,11 @@ struct _PEI_CORE_INSTANCE { //=0D EFI_GUID *TempFileGuid;=0D =0D + //=0D + // Pointer to the memory attribute PPI=0D + //=0D + EDKII_MEMORY_ATTRIBUTE_PPI *MemoryAttributePpi;=0D +=0D //=0D // Temp Memory Range is not covered by PeiTempMem and Stack.=0D // Those Memory Range will be migrated into physical memory.=0D diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiM= ain.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=0D gEfiSecHobDataPpiGuid ## SOMETIMES_CONSUMES=0D gEfiPeiCoreFvLocationPpiGuid ## SOMETIMES_CONSUMES=0D + gEdkiiMemoryAttributePpiGuid ## SOMETIMES_CONSUMES=0D =0D [Pcd]=0D gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize = ## CONSUMES=0D --=20 2.39.2