From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-it0-x22f.google.com (mail-it0-x22f.google.com [IPv6:2607:f8b0:4001:c0b::22f]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 8562082011 for ; Mon, 6 Feb 2017 06:34:48 -0800 (PST) Received: by mail-it0-x22f.google.com with SMTP id 203so55598606ith.0 for ; Mon, 06 Feb 2017 06:34:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=cYMpjnN7FD4HE+s27wSwyEtrEcRAhKTgxBjpkZmm3Cc=; b=hhBFybQXZz4pIP0A2TIMIYepcnqg7B15ojPeLs0YPdlqiqf2KlEwGvj00U1qT9DH6L aU8colndwzsNXIKXLVGUMFEijy/JBjm8GZCz0y2YzFN25YXYZH22ROaazEKNPsfQ4LBn tk2sJoFNrpSrPY/N+kZWVRw8zjwbqHj+3wqBc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=cYMpjnN7FD4HE+s27wSwyEtrEcRAhKTgxBjpkZmm3Cc=; b=arV2fdinMN5DbBUj2JSiONM/zY8G5afdmmyqmpRg9XqoWaEfAlGjHfeCtFWxYbrpTO xojkAwbQVcNuUb4H04eo95wN53WMhnEz7z/4tDT2/Q6kkfpz5mxqgXyq/LlFf1hv+z8R UnsYs8RHozQpQxUSyeMGK1VRl4ib1LQqHD/9rTzHSt3OsBmJgUc6iPwcI1YV4HHh1VqQ sdCFp3XsiknJsOeRdR+88v/ZyOX80mbMrC288cT48o5Ckj4Lz9RPjjdNdBmJOYqftgNY 5xB7Uwp599LrZeUPYPNT5XyxWAa2OsZKVpTAvrC3R+fCeIPl9H5C947jzeHdXcxJWeYu s9og== X-Gm-Message-State: AIkVDXJiGWkG+6efFIT4q8QuLxEm4OX8jWB0dMGH5CMQ9YoJ37+8M5DKJh4iPxnNDo1sBve+KHO4pbqb8tfcIai3 X-Received: by 10.36.207.212 with SMTP id y203mr7042902itf.63.1486391687585; Mon, 06 Feb 2017 06:34:47 -0800 (PST) MIME-Version: 1.0 Received: by 10.107.144.139 with HTTP; Mon, 6 Feb 2017 06:34:47 -0800 (PST) In-Reply-To: <1485419955-26652-4-git-send-email-jiewen.yao@intel.com> References: <1485419955-26652-1-git-send-email-jiewen.yao@intel.com> <1485419955-26652-4-git-send-email-jiewen.yao@intel.com> From: Ard Biesheuvel Date: Mon, 6 Feb 2017 14:34:47 +0000 Message-ID: To: Jiewen Yao Cc: "edk2-devel@lists.01.org" , Michael Kinney , Feng Tian , Star Zeng Subject: Re: [PATCH 3/3] MdeModulePkg/DxeCore: Add UEFI image protection. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 06 Feb 2017 14:34:48 -0000 Content-Type: text/plain; charset=UTF-8 On 26 January 2017 at 08:39, Jiewen Yao wrote: > If the UEFI image is page aligned, the image code section is set to read > only and the image data section is set to non-executable. > > 1) This policy is applied for all UEFI image including boot service driver, > runtime driver or application. > 2) This policy is applied only if the UEFI image meets the page alignment > requirement. > 3) This policy is applied only if the UEFI image is from firmware volume. > If the image is from OPROM, file system, or network, this policy is not > applied, even if the image meets the page alignment requirement. Is this policy configurable? I would like to start enforcing this on ARM even for file system images. > 4) This policy is not applied to the non-PE image region. > > The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect > the image. If the CpuArch protocol is not installed yet, the DxeCore > enqueues the protection request. Once the CpuArch is installed, the > DxeCore dequeues the protection request and applies policy. > > Once the image is unloaded, the protection is removed automatically. > > Cc: Star Zeng > Cc: Feng Tian > Cc: Michael Kinney > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Jiewen Yao > --- > MdeModulePkg/Core/Dxe/DxeMain.h | 53 ++ > MdeModulePkg/Core/Dxe/DxeMain.inf | 2 + > MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c | 1 + > MdeModulePkg/Core/Dxe/Image/Image.c | 5 + > MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c | 822 ++++++++++++++++++++ > MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c | 22 - > 6 files changed, 883 insertions(+), 22 deletions(-) > > diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h > index ae35fbb..67b5a5a 100644 > --- a/MdeModulePkg/Core/Dxe/DxeMain.h > +++ b/MdeModulePkg/Core/Dxe/DxeMain.h > @@ -267,6 +267,26 @@ typedef struct { > #define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ > CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE) > > +#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C') > + > +typedef struct { > + UINT32 Signature; > + LIST_ENTRY Link; > + EFI_PHYSICAL_ADDRESS CodeSegmentBase; > + UINT64 CodeSegmentSize; > +} IMAGE_PROPERTIES_RECORD_CODE_SECTION; > + > +#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D') > + > +typedef struct { > + UINT32 Signature; > + LIST_ENTRY Link; > + EFI_PHYSICAL_ADDRESS ImageBase; > + UINT64 ImageSize; > + UINTN CodeSegmentCount; > + LIST_ENTRY CodeSegmentList; > +} IMAGE_PROPERTIES_RECORD; > + > // > // DXE Core Global Variables > // > @@ -2859,6 +2879,15 @@ CoreInitializeMemoryAttributesTable ( > ); > > /** > + Initialize Memory Protection support. > +**/ > +VOID > +EFIAPI > +CoreInitializeMemoryProtection ( > + VOID > + ); > + > +/** > Install MemoryAttributesTable on memory allocation. > > @param[in] MemoryType EFI memory type. > @@ -2888,4 +2917,28 @@ RemoveImageRecord ( > IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage > ); > > +/** > + Protect UEFI image. > + > + @param[in] LoadedImage The loaded image protocol > + @param[in] LoadedImageDevicePath The loaded image device path protocol > +**/ > +VOID > +ProtectUefiImage ( > + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, > + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath > + ); > + > +/** > + Unprotect UEFI image. > + > + @param[in] LoadedImage The loaded image protocol > + @param[in] LoadedImageDevicePath The loaded image device path protocol > +**/ > +VOID > +UnprotectUefiImage ( > + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, > + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath > + ); > + > #endif > diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf > index 13a2381..e62bc42 100644 > --- a/MdeModulePkg/Core/Dxe/DxeMain.inf > +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf > @@ -42,6 +42,7 @@ > Misc/InstallConfigurationTable.c > Misc/PropertiesTable.c > Misc/MemoryAttributesTable.c > + Misc/MemoryProtection.c > Library/Library.c > Hand/DriverSupport.c > Hand/Notify.c > @@ -159,6 +160,7 @@ > gEfiHiiPackageListProtocolGuid ## SOMETIMES_PRODUCES > gEfiEbcProtocolGuid ## SOMETIMES_CONSUMES > gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES > + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES > > # Arch Protocols > gEfiBdsArchProtocolGuid ## CONSUMES > diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c > index 21cd61a..7304f69 100644 > --- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c > +++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c > @@ -398,6 +398,7 @@ DxeMain ( > > CoreInitializePropertiesTable (); > CoreInitializeMemoryAttributesTable (); > + CoreInitializeMemoryProtection (); > > // > // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated, > diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c > index 4a8a16d..1c930ef 100644 > --- a/MdeModulePkg/Core/Dxe/Image/Image.c > +++ b/MdeModulePkg/Core/Dxe/Image/Image.c > @@ -203,6 +203,8 @@ CoreInitializeImageServices ( > ); > } > > + ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); > + > return Status; > } > > @@ -862,6 +864,8 @@ CoreUnloadAndCloseImage ( > UnregisterMemoryProfileImage (Image); > } > > + UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath); > + > if (Image->Ebc != NULL) { > // > // If EBC protocol exists we must perform cleanups for this image. > @@ -1341,6 +1345,7 @@ CoreLoadImageCommon ( > goto Done; > } > } > + ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); > > // > // Success. Return the image handle > diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c > new file mode 100644 > index 0000000..fe412a0 > --- /dev/null > +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c > @@ -0,0 +1,822 @@ > +/** @file > + UEFI Memory Protection support. > + > + If the UEFI image is page aligned, the image code section is set to read only > + and the image data section is set to non-executable. > + > + 1) This policy is applied for all UEFI image including boot service driver, > + runtime driver or application. > + 2) This policy is applied only if the UEFI image meets the page alignment > + requirement. > + 3) This policy is applied only if the UEFI image is from firmware volume. > + If the image is from OPROM, file system, or network, this policy is not > + applied, even if the image meets the page alignment requirement. > + 4) This policy is not applied to the non-PE image region. > + > + The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect > + the image. If the CpuArch protocol is not installed yet, the DxeCore > + enqueues the protection request. Once the CpuArch is installed, the > + DxeCore dequeues the protection request and applies policy. > + > + Once the image is unloaded, the protection is removed automatically. > + > +Copyright (c) 2016, Intel Corporation. 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 > + > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "DxeMain.h" > + > +#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP) > +#define MEMORY_ATTRIBUTE_MASK (EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RO) > + > +// > +// Image type definitions > +// > +#define IMAGE_UNKNOWN 0x00000001 > +#define IMAGE_FROM_FV 0x00000002 > +#define IMAGE_FROM_OPTION_ROM 0x00000004 > +#define IMAGE_FROM_REMOVABLE_MEDIA 0x00000008 > +#define IMAGE_FROM_FIXED_MEDIA 0x00000010 > + > +// > +// Protection policy bit definition > +// > +#define DO_NOT_PROTECT 0x00000000 > +#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001 > + > +UINT32 mDefaultProtectionPolicy[] = { > + DO_NOT_PROTECT, // IMAGE_UNKNOWN > + PROTECT_IF_ALIGNED_ELSE_ALLOW, // IMAGE_FROM_FV > + DO_NOT_PROTECT, // IMAGE_FROM_OPTION_ROM > + DO_NOT_PROTECT, // IMAGE_FROM_REMOVABLE_MEDIA > + DO_NOT_PROTECT, // IMAGE_FROM_FIXED_MEDIA > +}; > + > +/** > + Sort code section in image record, based upon CodeSegmentBase from low to high. > + > + @param ImageRecord image record to be sorted > +**/ > +VOID > +SortImageRecordCodeSection ( > + IN IMAGE_PROPERTIES_RECORD *ImageRecord > + ); > + > +/** > + Check if code section in image record is valid. > + > + @param ImageRecord image record to be checked > + > + @retval TRUE image record is valid > + @retval FALSE image record is invalid > +**/ > +BOOLEAN > +IsImageRecordCodeSectionValid ( > + IN IMAGE_PROPERTIES_RECORD *ImageRecord > + ); > + > +/** > + Get the image type. > + > + @param[in] File This is a pointer to the device path of the file that is > + being dispatched. > + > + @return UINT32 Image Type > +**/ > +UINT32 > +GetImageType ( > + IN CONST EFI_DEVICE_PATH_PROTOCOL *File > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE DeviceHandle; > + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; > + EFI_BLOCK_IO_PROTOCOL *BlockIo; > + > + if (File == NULL) { > + return IMAGE_UNKNOWN; > + } > + > + // > + // First check to see if File is from a Firmware Volume > + // > + DeviceHandle = NULL; > + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; > + Status = gBS->LocateDevicePath ( > + &gEfiFirmwareVolume2ProtocolGuid, > + &TempDevicePath, > + &DeviceHandle > + ); > + if (!EFI_ERROR (Status)) { > + Status = gBS->OpenProtocol ( > + DeviceHandle, > + &gEfiFirmwareVolume2ProtocolGuid, > + NULL, > + NULL, > + NULL, > + EFI_OPEN_PROTOCOL_TEST_PROTOCOL > + ); > + if (!EFI_ERROR (Status)) { > + return IMAGE_FROM_FV; > + } > + } > + > + // > + // Next check to see if File is from a Block I/O device > + // > + DeviceHandle = NULL; > + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; > + Status = gBS->LocateDevicePath ( > + &gEfiBlockIoProtocolGuid, > + &TempDevicePath, > + &DeviceHandle > + ); > + if (!EFI_ERROR (Status)) { > + BlockIo = NULL; > + Status = gBS->OpenProtocol ( > + DeviceHandle, > + &gEfiBlockIoProtocolGuid, > + (VOID **) &BlockIo, > + NULL, > + NULL, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (!EFI_ERROR (Status) && BlockIo != NULL) { > + if (BlockIo->Media != NULL) { > + if (BlockIo->Media->RemovableMedia) { > + // > + // Block I/O is present and specifies the media is removable > + // > + return IMAGE_FROM_REMOVABLE_MEDIA; > + } else { > + // > + // Block I/O is present and specifies the media is not removable > + // > + return IMAGE_FROM_FIXED_MEDIA; > + } > + } > + } > + } > + > + // > + // File is not in a Firmware Volume or on a Block I/O device, so check to see if > + // the device path supports the Simple File System Protocol. > + // > + DeviceHandle = NULL; > + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; > + Status = gBS->LocateDevicePath ( > + &gEfiSimpleFileSystemProtocolGuid, > + &TempDevicePath, > + &DeviceHandle > + ); > + if (!EFI_ERROR (Status)) { > + // > + // Simple File System is present without Block I/O, so assume media is fixed. > + // > + return IMAGE_FROM_FIXED_MEDIA; > + } > + > + // > + // File is not from an FV, Block I/O or Simple File System, so the only options > + // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. > + // > + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; > + while (!IsDevicePathEndType (TempDevicePath)) { > + switch (DevicePathType (TempDevicePath)) { > + > + case MEDIA_DEVICE_PATH: > + if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) { > + return IMAGE_FROM_OPTION_ROM; > + } > + break; > + > + case MESSAGING_DEVICE_PATH: > + if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) { > + return IMAGE_FROM_REMOVABLE_MEDIA; > + } > + break; > + > + default: > + break; > + } > + TempDevicePath = NextDevicePathNode (TempDevicePath); > + } > + return IMAGE_UNKNOWN; > +} > + > +/** > + Get UEFI image protection policy based upon image type. > + > + @param[in] ImageType The UEFI image type > + > + @return UEFI image protection policy > +**/ > +UINT32 > +GetProtectionPolicyFromImageType ( > + IN UINT32 ImageType > + ) > +{ > + UINTN Index; > + > + for (Index = 0; Index < ARRAY_SIZE(mDefaultProtectionPolicy); Index++) { > + if ((UINT32)(1 << Index) == ImageType) { > + return mDefaultProtectionPolicy[Index]; > + } > + } > + return DO_NOT_PROTECT; > +} > + > +/** > + Get UEFI image protection policy based upon loaded image device path. > + > + @param[in] LoadedImage The loaded image protocol > + @param[in] LoadedImageDevicePath The loaded image device path protocol > + > + @return UEFI image protection policy > +**/ > +UINT32 > +GetUefiImageProtectionPolicy ( > + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, > + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath > + ) > +{ > + BOOLEAN InSmm; > + UINT32 ImageType; > + UINT32 ProtectionPolicy; > + > + // > + // Check SMM > + // > + InSmm = FALSE; > + if (gSmmBase2 != NULL) { > + gSmmBase2->InSmm (gSmmBase2, &InSmm); > + } > + if (InSmm) { > + return FALSE; > + } > + > + // > + // Check DevicePath > + // > + if (LoadedImage == gDxeCoreLoadedImage) { > + ImageType = IMAGE_FROM_FV; > + } else { > + ImageType = GetImageType (LoadedImageDevicePath); > + } > + ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType); > + return ProtectionPolicy; > +} > + > + > +/** > + Set UEFI image memory attributes. > + > + @param[in] BaseAddress Specified start address > + @param[in] Length Specified length > + @param[in] Attributes Specified attributes > +**/ > +VOID > +SetUefiImageMemoryAttributes ( > + IN UINT64 BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes > + ) > +{ > + EFI_STATUS Status; > + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; > + UINT64 FinalAttributes; > + > + Status = CoreGetMemorySpaceDescriptor(BaseAddress, &Descriptor); > + ASSERT_EFI_ERROR(Status); > + > + FinalAttributes = (Descriptor.Attributes & CACHE_ATTRIBUTE_MASK) | (Attributes & MEMORY_ATTRIBUTE_MASK); > + > + DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes)); > + > + ASSERT(gCpu != NULL); > + gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes); > +} > + > +/** > + Set UEFI image protection attributes. > + > + @param[in] ImageRecord A UEFI image record > + @param[in] Protect TRUE: Protect the UEFI image. > + FALSE: Unprotect the UEFI image. > +**/ > +VOID > +SetUefiImageProtectionAttributes ( > + IN IMAGE_PROPERTIES_RECORD *ImageRecord, > + IN BOOLEAN Protect > + ) > +{ > + IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; > + LIST_ENTRY *ImageRecordCodeSectionLink; > + LIST_ENTRY *ImageRecordCodeSectionEndLink; > + LIST_ENTRY *ImageRecordCodeSectionList; > + UINT64 CurrentBase; > + UINT64 ImageEnd; > + UINT64 Attribute; > + > + ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; > + > + CurrentBase = ImageRecord->ImageBase; > + ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize; > + > + ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; > + ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; > + while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { > + ImageRecordCodeSection = CR ( > + ImageRecordCodeSectionLink, > + IMAGE_PROPERTIES_RECORD_CODE_SECTION, > + Link, > + IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE > + ); > + ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; > + > + ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase); > + if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) { > + // > + // DATA > + // > + if (Protect) { > + Attribute = EFI_MEMORY_XP; > + } else { > + Attribute = 0; > + } > + SetUefiImageMemoryAttributes ( > + CurrentBase, > + ImageRecordCodeSection->CodeSegmentBase - CurrentBase, > + Attribute > + ); > + } > + // > + // CODE > + // > + if (Protect) { > + Attribute = EFI_MEMORY_RO; > + } else { > + Attribute = 0; > + } > + SetUefiImageMemoryAttributes ( > + ImageRecordCodeSection->CodeSegmentBase, > + ImageRecordCodeSection->CodeSegmentSize, > + Attribute > + ); > + CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize; > + } > + // > + // Last DATA > + // > + ASSERT (CurrentBase <= ImageEnd); > + if (CurrentBase < ImageEnd) { > + // > + // DATA > + // > + if (Protect) { > + Attribute = EFI_MEMORY_XP; > + } else { > + Attribute = 0; > + } > + SetUefiImageMemoryAttributes ( > + CurrentBase, > + ImageEnd - CurrentBase, > + Attribute > + ); > + } > + return ; > +} > + > +/** > + Return if the PE image section is aligned. > + > + @param[in] SectionAlignment PE/COFF section alignment > + @param[in] MemoryType PE/COFF image memory type > + > + @retval TRUE The PE image section is aligned. > + @retval FALSE The PE image section is not aligned. > +**/ > +BOOLEAN > +IsMemoryProtectionSectionAligned ( > + IN UINT32 SectionAlignment, > + IN EFI_MEMORY_TYPE MemoryType > + ) > +{ > + UINT32 PageAlignment; > + > + switch (MemoryType) { > + case EfiRuntimeServicesCode: > + case EfiACPIMemoryNVS: > + PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; > + break; > + case EfiRuntimeServicesData: > + case EfiACPIReclaimMemory: > + ASSERT (FALSE); > + PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; > + break; > + case EfiBootServicesCode: > + case EfiLoaderCode: > + case EfiReservedMemoryType: > + PageAlignment = EFI_PAGE_SIZE; > + break; > + default: > + ASSERT (FALSE); > + PageAlignment = EFI_PAGE_SIZE; > + break; > + } > + > + if ((SectionAlignment & (PageAlignment - 1)) != 0) { > + return FALSE; > + } else { > + return TRUE; > + } > +} > + > +/** > + Free Image record. > + > + @param[in] ImageRecord A UEFI image record > +**/ > +VOID > +FreeImageRecord ( > + IN IMAGE_PROPERTIES_RECORD *ImageRecord > + ) > +{ > + LIST_ENTRY *CodeSegmentListHead; > + IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; > + > + CodeSegmentListHead = &ImageRecord->CodeSegmentList; > + while (!IsListEmpty (CodeSegmentListHead)) { > + ImageRecordCodeSection = CR ( > + CodeSegmentListHead->ForwardLink, > + IMAGE_PROPERTIES_RECORD_CODE_SECTION, > + Link, > + IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE > + ); > + RemoveEntryList (&ImageRecordCodeSection->Link); > + FreePool (ImageRecordCodeSection); > + } > + > + if (ImageRecord->Link.ForwardLink != NULL) { > + RemoveEntryList (&ImageRecord->Link); > + } > + FreePool (ImageRecord); > +} > + > +/** > + Protect or unprotect UEFI image common function. > + > + @param[in] LoadedImage The loaded image protocol > + @param[in] LoadedImageDevicePath The loaded image device path protocol > + @param[in] Protect TRUE: Protect the UEFI image. > + FALSE: Unprotect the UEFI image. > +**/ > +VOID > +ProtectUefiImageCommon ( > + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, > + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath, > + IN BOOLEAN Protect > + ) > +{ > + VOID *ImageAddress; > + EFI_IMAGE_DOS_HEADER *DosHdr; > + UINT32 PeCoffHeaderOffset; > + UINT32 SectionAlignment; > + EFI_IMAGE_SECTION_HEADER *Section; > + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; > + UINT8 *Name; > + UINTN Index; > + IMAGE_PROPERTIES_RECORD *ImageRecord; > + CHAR8 *PdbPointer; > + IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; > + UINT16 Magic; > + BOOLEAN IsAligned; > + UINT32 ProtectionPolicy; > + > + DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage)); > + DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize)); > + > + if (gCpu == NULL) { > + return ; > + } > + > + ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath); > + switch (ProtectionPolicy) { > + case DO_NOT_PROTECT: > + return ; > + case PROTECT_IF_ALIGNED_ELSE_ALLOW: > + break; > + default: > + ASSERT(FALSE); > + return ; > + } > + > + ImageRecord = AllocateZeroPool (sizeof(*ImageRecord)); > + if (ImageRecord == NULL) { > + return ; > + } > + ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE; > + > + // > + // Step 1: record whole region > + // > + ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase; > + ImageRecord->ImageSize = LoadedImage->ImageSize; > + > + ImageAddress = LoadedImage->ImageBase; > + > + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress); > + if (PdbPointer != NULL) { > + DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer)); > + } > + > + // > + // Check PE/COFF image > + // > + DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress; > + PeCoffHeaderOffset = 0; > + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { > + PeCoffHeaderOffset = DosHdr->e_lfanew; > + } > + > + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset); > + if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { > + DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature)); > + // It might be image in SMM. > + goto Finish; > + } > + > + // > + // Get SectionAlignment > + // > + if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { > + // > + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value > + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the > + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC > + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC > + // > + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; > + } else { > + // > + // Get the magic value from the PE/COFF Optional Header > + // > + Magic = Hdr.Pe32->OptionalHeader.Magic; > + } > + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { > + SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment; > + } else { > + SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment; > + } > + > + IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType); > + if (!IsAligned) { > + DEBUG ((DEBUG_VERBOSE, "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n", > + SectionAlignment)); > + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress); > + if (PdbPointer != NULL) { > + DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); > + } > + goto Finish; > + } > + > + Section = (EFI_IMAGE_SECTION_HEADER *) ( > + (UINT8 *) (UINTN) ImageAddress + > + PeCoffHeaderOffset + > + sizeof(UINT32) + > + sizeof(EFI_IMAGE_FILE_HEADER) + > + Hdr.Pe32->FileHeader.SizeOfOptionalHeader > + ); > + ImageRecord->CodeSegmentCount = 0; > + InitializeListHead (&ImageRecord->CodeSegmentList); > + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { > + Name = Section[Index].Name; > + DEBUG (( > + DEBUG_VERBOSE, > + " Section - '%c%c%c%c%c%c%c%c'\n", > + Name[0], > + Name[1], > + Name[2], > + Name[3], > + Name[4], > + Name[5], > + Name[6], > + Name[7] > + )); > + > + if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) { > + DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize)); > + DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress)); > + DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData)); > + DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData)); > + DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations)); > + DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers)); > + DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations)); > + DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers)); > + DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics)); > + > + // > + // Step 2: record code section > + // > + ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection)); > + if (ImageRecordCodeSection == NULL) { > + return ; > + } > + ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE; > + > + ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress; > + ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE(Section[Index].SizeOfRawData, SectionAlignment); > + > + DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize)); > + > + InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link); > + ImageRecord->CodeSegmentCount++; > + } > + } > + > + if (ImageRecord->CodeSegmentCount == 0) { > + DEBUG ((DEBUG_ERROR, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n")); > + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress); > + if (PdbPointer != NULL) { > + DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); > + } > + goto Finish; > + } > + > + // > + // Final > + // > + SortImageRecordCodeSection (ImageRecord); > + // > + // Check overlap all section in ImageBase/Size > + // > + if (!IsImageRecordCodeSectionValid (ImageRecord)) { > + DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n")); > + goto Finish; > + } > + > + // > + // CPU ARCH present. Update memory attribute directly. > + // > + SetUefiImageProtectionAttributes (ImageRecord, Protect); > + > + // > + // Clean up > + // > + FreeImageRecord (ImageRecord); > + > +Finish: > + return ; > +} > + > +/** > + Protect UEFI image. > + > + @param[in] LoadedImage The loaded image protocol > + @param[in] LoadedImageDevicePath The loaded image device path protocol > +**/ > +VOID > +ProtectUefiImage ( > + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, > + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath > + ) > +{ > + ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, TRUE); > +} > + > +/** > + Unprotect UEFI image. > + > + @param[in] LoadedImage The loaded image protocol > + @param[in] LoadedImageDevicePath The loaded image device path protocol > +**/ > +VOID > +UnprotectUefiImage ( > + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, > + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath > + ) > +{ > + ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, FALSE); > +} > + > +/** > + A notification for CPU_ARCH protocol. > + > + @param[in] Event Event whose notification function is being invoked. > + @param[in] Context Pointer to the notification function's context, > + which is implementation-dependent. > + > +**/ > +VOID > +EFIAPI > +MemoryProtectionCpuArchProtocolNotify ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; > + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; > + UINTN NoHandles; > + EFI_HANDLE *HandleBuffer; > + UINTN Index; > + > + DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n")); > + Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu); > + if (EFI_ERROR (Status)) { > + return; > + } > + > + Status = gBS->LocateHandleBuffer ( > + ByProtocol, > + &gEfiLoadedImageProtocolGuid, > + NULL, > + &NoHandles, > + &HandleBuffer > + ); > + if (EFI_ERROR (Status) && (NoHandles == 0)) { > + return ; > + } > + > + for (Index = 0; Index < NoHandles; Index++) { > + Status = gBS->HandleProtocol ( > + HandleBuffer[Index], > + &gEfiLoadedImageProtocolGuid, > + (VOID **)&LoadedImage > + ); > + if (EFI_ERROR(Status)) { > + continue; > + } > + Status = gBS->HandleProtocol ( > + HandleBuffer[Index], > + &gEfiLoadedImageDevicePathProtocolGuid, > + (VOID **)&LoadedImageDevicePath > + ); > + if (EFI_ERROR(Status)) { > + LoadedImageDevicePath = NULL; > + } > + > + ProtectUefiImage (LoadedImage, LoadedImageDevicePath); > + } > + > + CoreCloseEvent (Event); > + return; > +} > + > +/** > + Initialize Memory Protection support. > +**/ > +VOID > +EFIAPI > +CoreInitializeMemoryProtection ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_EVENT Event; > + VOID *Registration; > + > + Status = CoreCreateEvent ( > + EVT_NOTIFY_SIGNAL, > + TPL_CALLBACK, > + MemoryProtectionCpuArchProtocolNotify, > + NULL, > + &Event > + ); > + ASSERT_EFI_ERROR(Status); > + > + // > + // Register for protocol notifactions on this event > + // > + Status = CoreRegisterProtocolNotify ( > + &gEfiCpuArchProtocolGuid, > + Event, > + &Registration > + ); > + ASSERT_EFI_ERROR(Status); > + return ; > +} > diff --git a/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c b/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c > index 7ecad89..a18c02d 100644 > --- a/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c > +++ b/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c > @@ -36,26 +36,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ > ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size))) > > -#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C') > - > -typedef struct { > - UINT32 Signature; > - LIST_ENTRY Link; > - EFI_PHYSICAL_ADDRESS CodeSegmentBase; > - UINT64 CodeSegmentSize; > -} IMAGE_PROPERTIES_RECORD_CODE_SECTION; > - > -#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D') > - > -typedef struct { > - UINT32 Signature; > - LIST_ENTRY Link; > - EFI_PHYSICAL_ADDRESS ImageBase; > - UINT64 ImageSize; > - UINTN CodeSegmentCount; > - LIST_ENTRY CodeSegmentList; > -} IMAGE_PROPERTIES_RECORD; > - > #define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D') > > typedef struct { > @@ -864,7 +844,6 @@ SwapImageRecordCodeSection ( > > @param ImageRecord image record to be sorted > **/ > -STATIC > VOID > SortImageRecordCodeSection ( > IN IMAGE_PROPERTIES_RECORD *ImageRecord > @@ -915,7 +894,6 @@ SortImageRecordCodeSection ( > @retval TRUE image record is valid > @retval FALSE image record is invalid > **/ > -STATIC > BOOLEAN > IsImageRecordCodeSectionValid ( > IN IMAGE_PROPERTIES_RECORD *ImageRecord > -- > 2.7.4.windows.1 > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel