audk/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c

1285 lines
40 KiB
C
Raw Normal View History

MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
/** @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 Source UEFI image matches the
PcdImageProtectionPolicy definition.
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) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
**/
#include <PiDxe.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiLib.h>
#include <Guid/EventGroup.h>
#include <Guid/MemoryAttributesTable.h>
#include <Protocol/FirmwareVolume2.h>
#include <Protocol/SimpleFileSystem.h>
#include "DxeMain.h"
#include "Mem/HeapGuard.h"
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
//
// Image type definitions
//
#define IMAGE_UNKNOWN 0x00000001
#define IMAGE_FROM_FV 0x00000002
//
// Protection policy bit definition
//
#define DO_NOT_PROTECT 0x00000000
#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001
#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
UINT32 mImageProtectionPolicy;
extern LIST_ENTRY mGcdMemorySpaceMap;
STATIC LIST_ENTRY mProtectedImageRecordList;
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
/**
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;
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;
}
}
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
)
{
if ((ImageType & mImageProtectionPolicy) == 0) {
return DO_NOT_PROTECT;
} else {
return PROTECT_IF_ALIGNED_ELSE_ALLOW;
}
}
/**
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 & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
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
**/
VOID
SetUefiImageProtectionAttributes (
IN IMAGE_PROPERTIES_RECORD *ImageRecord
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
)
{
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
LIST_ENTRY *ImageRecordCodeSectionLink;
LIST_ENTRY *ImageRecordCodeSectionEndLink;
LIST_ENTRY *ImageRecordCodeSectionList;
UINT64 CurrentBase;
UINT64 ImageEnd;
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
//
SetUefiImageMemoryAttributes (
CurrentBase,
ImageRecordCodeSection->CodeSegmentBase - CurrentBase,
EFI_MEMORY_XP
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
);
}
//
// CODE
//
SetUefiImageMemoryAttributes (
ImageRecordCodeSection->CodeSegmentBase,
ImageRecordCodeSection->CodeSegmentSize,
EFI_MEMORY_RO
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
);
CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
}
//
// Last DATA
//
ASSERT (CurrentBase <= ImageEnd);
if (CurrentBase < ImageEnd) {
//
// DATA
//
SetUefiImageMemoryAttributes (
CurrentBase,
ImageEnd - CurrentBase,
EFI_MEMORY_XP
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
);
}
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 = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
break;
case EfiRuntimeServicesData:
case EfiACPIReclaimMemory:
ASSERT (FALSE);
PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
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 UEFI PE/COFF image.
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
@param[in] LoadedImage The loaded image protocol
@param[in] LoadedImageDevicePath The loaded image device path protocol
**/
VOID
ProtectUefiImage (
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
)
{
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;
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->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
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]
));
//
// Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE
// can always be mapped read-only, classify a section as a code section only
// if it has the executable attribute set and the writable attribute cleared.
//
// This adheres more closely to the PE/COFF spec, and avoids issues with
// Linux OS loaders that may consist of a single read/write/execute section.
//
if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
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) {
//
// If a UEFI executable consists of a single read+write+exec PE/COFF
// section, that isn't actually an error. The image can be launched
// alright, only image protection cannot be applied to it fully.
//
// One example that elicits this is (some) Linux kernels (with the EFI stub
// of course).
//
DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
if (PdbPointer != NULL) {
DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
}
goto Finish;
}
//
// Final
//
SortImageRecordCodeSection (ImageRecord);
//
// Check overlap all section in ImageBase/Size
//
if (!IsImageRecordCodeSectionValid (ImageRecord)) {
DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
goto Finish;
}
//
// Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
// Given that the loader always allocates full pages, we know the space after the image is not used.
//
ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);
//
// CPU ARCH present. Update memory attribute directly.
//
SetUefiImageProtectionAttributes (ImageRecord);
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
//
// Record the image record in the list so we can undo the protections later
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
//
InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
Finish:
return ;
}
/**
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
)
{
IMAGE_PROPERTIES_RECORD *ImageRecord;
LIST_ENTRY *ImageRecordLink;
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
if (PcdGet32(PcdImageProtectionPolicy) != 0) {
for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;
ImageRecordLink != &mProtectedImageRecordList;
ImageRecordLink = ImageRecordLink->ForwardLink) {
ImageRecord = CR (
ImageRecordLink,
IMAGE_PROPERTIES_RECORD,
Link,
IMAGE_PROPERTIES_RECORD_SIGNATURE
);
if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {
SetUefiImageMemoryAttributes (ImageRecord->ImageBase,
ImageRecord->ImageSize,
0);
FreeImageRecord (ImageRecord);
return;
}
}
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
}
}
/**
Return the EFI memory permission attribute associated with memory
type 'MemoryType' under the configured DXE memory protection policy.
@param MemoryType Memory type.
**/
STATIC
UINT64
GetPermissionAttributeForMemoryType (
IN EFI_MEMORY_TYPE MemoryType
)
{
UINT64 TestBit;
if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
TestBit = BIT63;
} else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
TestBit = BIT62;
} else {
TestBit = LShiftU64 (1, MemoryType);
}
if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {
return EFI_MEMORY_XP;
} else {
return 0;
}
}
/**
Sort memory map entries based upon PhysicalStart, from low to high.
@param MemoryMap A pointer to the buffer in which firmware places
the current memory map.
@param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
@param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
**/
STATIC
VOID
SortMemoryMap (
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN MemoryMapSize,
IN UINTN DescriptorSize
)
{
EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
EFI_MEMORY_DESCRIPTOR TempMemoryMap;
MemoryMapEntry = MemoryMap;
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
while (MemoryMapEntry < MemoryMapEnd) {
while (NextMemoryMapEntry < MemoryMapEnd) {
if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
}
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
}
MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
}
}
/**
Merge adjacent memory map entries if they use the same memory protection policy
@param[in, out] MemoryMap A pointer to the buffer in which firmware places
the current memory map.
@param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
MemoryMap buffer. On input, this is the size of
the current memory map. On output,
it is the size of new memory map after merge.
@param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
**/
STATIC
VOID
MergeMemoryMapForProtectionPolicy (
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN OUT UINTN *MemoryMapSize,
IN UINTN DescriptorSize
)
{
EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
UINT64 MemoryBlockLength;
EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
UINT64 Attributes;
SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
MemoryMapEntry = MemoryMap;
NewMemoryMapEntry = MemoryMap;
MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
do {
MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));
Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&
((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
if (NewMemoryMapEntry != MemoryMapEntry) {
NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
}
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
continue;
} else {
MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
break;
}
} while (TRUE);
MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
}
*MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
return ;
}
/**
Remove exec permissions from all regions whose type is identified by
PcdDxeNxMemoryProtectionPolicy.
**/
STATIC
VOID
InitializeDxeNxMemoryProtectionPolicy (
VOID
)
{
UINTN MemoryMapSize;
UINTN MapKey;
UINTN DescriptorSize;
UINT32 DescriptorVersion;
EFI_MEMORY_DESCRIPTOR *MemoryMap;
EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
EFI_STATUS Status;
UINT64 Attributes;
LIST_ENTRY *Link;
EFI_GCD_MAP_ENTRY *Entry;
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
EFI_PHYSICAL_ADDRESS StackBase;
//
// Get the EFI memory map.
//
MemoryMapSize = 0;
MemoryMap = NULL;
Status = gBS->GetMemoryMap (
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
do {
MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
ASSERT (MemoryMap != NULL);
Status = gBS->GetMemoryMap (
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
if (EFI_ERROR (Status)) {
FreePool (MemoryMap);
}
} while (Status == EFI_BUFFER_TOO_SMALL);
ASSERT_EFI_ERROR (Status);
StackBase = 0;
if (PcdGetBool (PcdCpuStackGuard)) {
//
// Get the base of stack from Hob.
//
Hob.Raw = GetHobList ();
while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
MemoryHob = Hob.MemoryAllocation;
if (CompareGuid(&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {
DEBUG ((
DEBUG_INFO,
"%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",
__FUNCTION__,
MemoryHob->AllocDescriptor.MemoryBaseAddress,
MemoryHob->AllocDescriptor.MemoryLength
));
StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;
//
// Ensure the base of the stack is page-size aligned.
//
ASSERT ((StackBase & EFI_PAGE_MASK) == 0);
break;
}
Hob.Raw = GET_NEXT_HOB (Hob);
}
//
// Ensure the base of stack can be found from Hob when stack guard is
// enabled.
//
ASSERT (StackBase != 0);
}
DEBUG ((
DEBUG_INFO,
"%a: applying strict permissions to active memory regions\n",
__FUNCTION__
));
MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);
MemoryMapEntry = MemoryMap;
MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
if (Attributes != 0) {
SetUefiImageMemoryAttributes (
MemoryMapEntry->PhysicalStart,
LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),
Attributes);
//
// Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is
// enabled.
//
if (MemoryMapEntry->PhysicalStart == 0 &&
PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0) {
ASSERT (MemoryMapEntry->NumberOfPages > 0);
SetUefiImageMemoryAttributes (
0,
EFI_PAGES_TO_SIZE (1),
EFI_MEMORY_RP | Attributes);
}
//
// Add EFI_MEMORY_RP attribute for the first page of the stack if stack
// guard is enabled.
//
if (StackBase != 0 &&
(StackBase >= MemoryMapEntry->PhysicalStart &&
StackBase < MemoryMapEntry->PhysicalStart +
LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT)) &&
PcdGetBool (PcdCpuStackGuard)) {
SetUefiImageMemoryAttributes (
StackBase,
EFI_PAGES_TO_SIZE (1),
EFI_MEMORY_RP | Attributes);
}
}
MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
}
FreePool (MemoryMap);
//
// Apply the policy for RAM regions that we know are present and
// accessible, but have not been added to the UEFI memory map (yet).
//
if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {
DEBUG ((
DEBUG_INFO,
"%a: applying strict permissions to inactive memory regions\n",
__FUNCTION__
));
CoreAcquireGcdMemoryLock ();
Link = mGcdMemorySpaceMap.ForwardLink;
while (Link != &mGcdMemorySpaceMap) {
Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
Entry->EndAddress < MAX_ADDRESS &&
(Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
(Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK);
DEBUG ((DEBUG_INFO,
"Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,
Attributes));
ASSERT(gCpu != NULL);
gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,
Entry->EndAddress - Entry->BaseAddress + 1, Attributes);
}
Link = Link->ForwardLink;
}
CoreReleaseGcdMemoryLock ();
}
}
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
/**
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)) {
goto Done;
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
}
//
// Apply the memory protection policy on non-BScode/RTcode regions.
//
if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {
InitializeDxeNxMemoryProtectionPolicy ();
}
MdeModulePkg/Core: allow HeapGuard even before CpuArchProtocol installed Due to the fact that HeapGuard needs CpuArchProtocol to update page attributes, the feature is normally enabled after CpuArchProtocol is installed. Since there're some drivers are loaded before CpuArchProtocl, they cannot make use HeapGuard feature to detect potential issues. This patch fixes above situation by updating the DXE core to skip the NULL check against global gCpu in the IsMemoryTypeToGuard(), and adding NULL check against gCpu in SetGuardPage() and UnsetGuardPage() to make sure that they can be called but do nothing. This will allow HeapGuard to record all guarded memory without setting the related Guard pages to not- present. Once the CpuArchProtocol is installed, a protocol notify will be called to complete the work of setting Guard pages to not-present. Please note that above changes will cause a #PF in GCD code during cleanup of map entries, which is initiated by CpuDxe driver to update real mtrr and paging attributes back to GCD. During that time, CpuDxe doesn't allow GCD to update memory attributes and then any Guard page cannot be unset. As a result, this will prevent Guarded memory from freeing during memory map cleanup. The solution is to avoid allocating guarded memory as memory map entries in GCD code. It's done by setting global mOnGuarding to TRUE before memory allocation and setting it back to FALSE afterwards in GCD function CoreAllocateGcdMapEntry(). Cc: Star Zeng <star.zeng@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jian J Wang <jian.j.wang@intel.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
2018-03-14 09:28:34 +01:00
//
// Call notify function meant for Heap Guard.
//
HeapGuardCpuArchProtocolNotify ();
if (mImageProtectionPolicy == 0) {
goto Done;
}
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiLoadedImageProtocolGuid,
NULL,
&NoHandles,
&HandleBuffer
);
if (EFI_ERROR (Status) && (NoHandles == 0)) {
goto Done;
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
}
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);
}
FreePool (HandleBuffer);
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
Done:
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
CoreCloseEvent (Event);
}
/**
ExitBootServices Callback function for memory protection.
**/
VOID
MemoryProtectionExitBootServicesCallback (
VOID
)
{
EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
LIST_ENTRY *Link;
//
// We need remove the RT protection, because RT relocation need write code segment
// at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.
//
// Firmware does not own page tables after ExitBootServices(), so the OS would
// have to relax protection of RT code pages across SetVirtualAddressMap(), or
// delay setting protections on RT code pages until after SetVirtualAddressMap().
// OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.
//
if (mImageProtectionPolicy != 0) {
for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {
RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);
}
}
}
/**
Disable NULL pointer detection after EndOfDxe. This is a workaround resort in
order to skip unfixable NULL pointer access issues detected in OptionROM or
boot loaders.
@param[in] Event The Event this notify function registered to.
@param[in] Context Pointer to the context data registered to the Event.
**/
VOID
EFIAPI
DisableNullDetectionAtTheEndOfDxe (
EFI_EVENT Event,
VOID *Context
)
{
EFI_STATUS Status;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));
//
// Disable NULL pointer detection by enabling first 4K page
//
Status = CoreGetMemorySpaceDescriptor (0, &Desc);
ASSERT_EFI_ERROR (Status);
if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
Status = CoreSetMemorySpaceCapabilities (
0,
EFI_PAGE_SIZE,
Desc.Capabilities | EFI_MEMORY_RP
);
ASSERT_EFI_ERROR (Status);
}
Status = CoreSetMemorySpaceAttributes (
0,
EFI_PAGE_SIZE,
Desc.Attributes & ~EFI_MEMORY_RP
);
ASSERT_EFI_ERROR (Status);
//
// Page 0 might have be allocated to avoid misuses. Free it here anyway.
//
CoreFreePages (0, 1);
CoreCloseEvent (Event);
DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));
return;
}
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
/**
Initialize Memory Protection support.
**/
VOID
EFIAPI
CoreInitializeMemoryProtection (
VOID
)
{
EFI_STATUS Status;
EFI_EVENT Event;
EFI_EVENT EndOfDxeEvent;
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
VOID *Registration;
mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);
InitializeListHead (&mProtectedImageRecordList);
//
// Sanity check the PcdDxeNxMemoryProtectionPolicy setting:
// - code regions should have no EFI_MEMORY_XP attribute
// - EfiConventionalMemory and EfiBootServicesData should use the
// same attribute
//
ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);
ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);
ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);
ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==
GetPermissionAttributeForMemoryType (EfiConventionalMemory));
MdeModulePkg/Core: fix ineffective guard page issue REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1295 This issue originates from following patch which allows to enable paging if PcdImageProtectionPolicy and PcdDxeNxMemoryProtectionPolicy (in addition to PcdSetNxForStack) are set to enable related features. 5267926134d17e86672b84fd57b438f05ffa68e1 Due to above change, PcdImageProtectionPolicy will be set to 0 by default in many platforms, which, in turn, cause following code in MdeModulePkg\Core\Dxe\Misc\MemoryProtection.c fail the creation of notify event of CpuArchProtocol. 1138: if (mImageProtectionPolicy != 0 || PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) { 1139: Status = CoreCreateEvent ( ... 1142: MemoryProtectionCpuArchProtocolNotify, ... 1145: ); Then following call flow won't be done and Guard pages will not be set as not-present in SetAllGuardPages() eventually. MemoryProtectionCpuArchProtocolNotify() => HeapGuardCpuArchProtocolNotify() => SetAllGuardPages() The solution is removing the if(...) statement so that the notify event will always be created and registered. This won't cause unnecessary code execution because, in the notify event handler, the related PCDs like PcdImageProtectionPolicy and PcdDxeNxMemoryProtectionPolicy will be checked again before doing related jobs. Cc: Star Zeng <star.zeng@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Ruiyu Ni <ruiyu.ni@intel.com> Cc: Leif Lindholm <leif.lindholm@linaro.org> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jian J Wang <jian.j.wang@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
2018-11-07 01:48:09 +01:00
Status = CoreCreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
MemoryProtectionCpuArchProtocolNotify,
NULL,
&Event
);
ASSERT_EFI_ERROR(Status);
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
MdeModulePkg/Core: fix ineffective guard page issue REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1295 This issue originates from following patch which allows to enable paging if PcdImageProtectionPolicy and PcdDxeNxMemoryProtectionPolicy (in addition to PcdSetNxForStack) are set to enable related features. 5267926134d17e86672b84fd57b438f05ffa68e1 Due to above change, PcdImageProtectionPolicy will be set to 0 by default in many platforms, which, in turn, cause following code in MdeModulePkg\Core\Dxe\Misc\MemoryProtection.c fail the creation of notify event of CpuArchProtocol. 1138: if (mImageProtectionPolicy != 0 || PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) { 1139: Status = CoreCreateEvent ( ... 1142: MemoryProtectionCpuArchProtocolNotify, ... 1145: ); Then following call flow won't be done and Guard pages will not be set as not-present in SetAllGuardPages() eventually. MemoryProtectionCpuArchProtocolNotify() => HeapGuardCpuArchProtocolNotify() => SetAllGuardPages() The solution is removing the if(...) statement so that the notify event will always be created and registered. This won't cause unnecessary code execution because, in the notify event handler, the related PCDs like PcdImageProtectionPolicy and PcdDxeNxMemoryProtectionPolicy will be checked again before doing related jobs. Cc: Star Zeng <star.zeng@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Ruiyu Ni <ruiyu.ni@intel.com> Cc: Leif Lindholm <leif.lindholm@linaro.org> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jian J Wang <jian.j.wang@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
2018-11-07 01:48:09 +01:00
//
// Register for protocol notifactions on this event
//
Status = CoreRegisterProtocolNotify (
&gEfiCpuArchProtocolGuid,
Event,
&Registration
);
ASSERT_EFI_ERROR(Status);
//
// Register a callback to disable NULL pointer detection at EndOfDxe
//
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))
== (BIT0|BIT7)) {
Status = CoreCreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
DisableNullDetectionAtTheEndOfDxe,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&EndOfDxeEvent
);
ASSERT_EFI_ERROR (Status);
}
MdeModulePkg/DxeCore: Add UEFI image protection. 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 Source UEFI image matches the PcdImageProtectionPolicy definition. 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. The UEFI runtime image protection is teared down at ExitBootServices(), the runtime image code relocation need write code segment at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. NOTE: It is per-requisite that code section and data section should not be not merged. That is same criteria for SMM/runtime driver. We are not able to detect during BIOS boot, because we can only get LINK warning below: "LINK : warning LNK4254: section '.data' (C0000040) merged into '.text' (60000020) with different attributes" But final attribute in PE code section is same. Cc: Star Zeng <star.zeng@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2017-01-14 08:04:10 +01:00
return ;
}
/**
Returns whether we are currently executing in SMM mode.
**/
STATIC
BOOLEAN
IsInSmm (
VOID
)
{
BOOLEAN InSmm;
InSmm = FALSE;
if (gSmmBase2 != NULL) {
gSmmBase2->InSmm (gSmmBase2, &InSmm);
}
return InSmm;
}
/**
Manage memory permission attributes on a memory range, according to the
configured DXE memory protection policy.
@param OldType The old memory type of the range
@param NewType The new memory type of the range
@param Memory The base address of the range
@param Length The size of the range (in bytes)
@return EFI_SUCCESS If we are executing in SMM mode. No permission attributes
are updated in this case
@return EFI_SUCCESS If the the CPU arch protocol is not installed yet
@return EFI_SUCCESS If no DXE memory protection policy has been configured
@return EFI_SUCCESS If OldType and NewType use the same permission attributes
@return other Return value of gCpu->SetMemoryAttributes()
**/
EFI_STATUS
EFIAPI
ApplyMemoryProtectionPolicy (
IN EFI_MEMORY_TYPE OldType,
IN EFI_MEMORY_TYPE NewType,
IN EFI_PHYSICAL_ADDRESS Memory,
IN UINT64 Length
)
{
UINT64 OldAttributes;
UINT64 NewAttributes;
//
// The policy configured in PcdDxeNxMemoryProtectionPolicy
// does not apply to allocations performed in SMM mode.
//
if (IsInSmm ()) {
return EFI_SUCCESS;
}
//
// If the CPU arch protocol is not installed yet, we cannot manage memory
// permission attributes, and it is the job of the driver that installs this
// protocol to set the permissions on existing allocations.
//
if (gCpu == NULL) {
return EFI_SUCCESS;
}
//
// Check if a DXE memory protection policy has been configured
//
if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {
return EFI_SUCCESS;
}
//
// Don't overwrite Guard pages, which should be the first and/or last page,
// if any.
//
MdeModulePkg/Core: add freed-memory guard feature Freed-memory guard is used to detect UAF (Use-After-Free) memory issue which is illegal access to memory which has been freed. The principle behind is similar to pool guard feature, that is we'll turn all pool memory allocation to page allocation and mark them to be not-present once they are freed. This also implies that, once a page is allocated and freed, it cannot be re-allocated. This will bring another issue, which is that there's risk that memory space will be used out. To address it, the memory service add logic to put part (at most 64 pages a time) of freed pages back into page pool, so that the memory service can still have memory to allocate, when all memory space have been allocated once. This is called memory promotion. The promoted pages are always from the eldest pages which haven been freed. This feature brings another problem is that memory map descriptors will be increased enormously (200+ -> 2000+). One of change in this patch is to update MergeMemoryMap() in file PropertiesTable.c to allow merge freed pages back into the memory map. Now the number can stay at around 510. Cc: Star Zeng <star.zeng@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Ruiyu Ni <ruiyu.ni@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jian J Wang <jian.j.wang@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
2018-10-24 06:47:45 +02:00
if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
if (IsGuardPage (Memory)) {
Memory += EFI_PAGE_SIZE;
Length -= EFI_PAGE_SIZE;
if (Length == 0) {
return EFI_SUCCESS;
}
}
if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {
Length -= EFI_PAGE_SIZE;
if (Length == 0) {
return EFI_SUCCESS;
}
}
}
//
// Update the executable permissions according to the DXE memory
// protection policy, but only if
// - the policy is different between the old and the new type, or
// - this is a newly added region (OldType == EfiMaxMemoryType)
//
NewAttributes = GetPermissionAttributeForMemoryType (NewType);
if (OldType != EfiMaxMemoryType) {
OldAttributes = GetPermissionAttributeForMemoryType (OldType);
if (OldAttributes == NewAttributes) {
// policy is the same between OldType and NewType
return EFI_SUCCESS;
}
} else if (NewAttributes == 0) {
// newly added region of a type that does not require protection
return EFI_SUCCESS;
}
return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);
}