#define DO_NOT_PROTECT 0x00000000\r
#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001\r
\r
+#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000\r
+#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000\r
+\r
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
+\r
UINT32 mImageProtectionPolicy;\r
\r
+extern LIST_ENTRY mGcdMemorySpaceMap;\r
+\r
+STATIC LIST_ENTRY mProtectedImageRecordList;\r
+\r
/**\r
Sort code section in image record, based upon CodeSegmentBase from low to high.\r
\r
Set UEFI image protection attributes.\r
\r
@param[in] ImageRecord A UEFI image record\r
- @param[in] Protect TRUE: Protect the UEFI image.\r
- FALSE: Unprotect the UEFI image.\r
**/\r
VOID\r
SetUefiImageProtectionAttributes (\r
- IN IMAGE_PROPERTIES_RECORD *ImageRecord,\r
- IN BOOLEAN Protect\r
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
)\r
{\r
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
LIST_ENTRY *ImageRecordCodeSectionList;\r
UINT64 CurrentBase;\r
UINT64 ImageEnd;\r
- UINT64 Attribute;\r
\r
ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
\r
//\r
// DATA\r
//\r
- if (Protect) {\r
- Attribute = EFI_MEMORY_XP;\r
- } else {\r
- Attribute = 0;\r
- }\r
SetUefiImageMemoryAttributes (\r
CurrentBase,\r
ImageRecordCodeSection->CodeSegmentBase - CurrentBase,\r
- Attribute\r
+ EFI_MEMORY_XP\r
);\r
}\r
//\r
// CODE\r
//\r
- if (Protect) {\r
- Attribute = EFI_MEMORY_RO;\r
- } else {\r
- Attribute = 0;\r
- }\r
SetUefiImageMemoryAttributes (\r
ImageRecordCodeSection->CodeSegmentBase,\r
ImageRecordCodeSection->CodeSegmentSize,\r
- Attribute\r
+ EFI_MEMORY_RO\r
);\r
CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;\r
}\r
//\r
// DATA\r
//\r
- if (Protect) {\r
- Attribute = EFI_MEMORY_XP;\r
- } else {\r
- Attribute = 0;\r
- }\r
SetUefiImageMemoryAttributes (\r
CurrentBase,\r
ImageEnd - CurrentBase,\r
- Attribute\r
+ EFI_MEMORY_XP\r
);\r
}\r
return ;\r
switch (MemoryType) {\r
case EfiRuntimeServicesCode:\r
case EfiACPIMemoryNVS:\r
- PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
+ PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
break;\r
case EfiRuntimeServicesData:\r
case EfiACPIReclaimMemory:\r
ASSERT (FALSE);\r
- PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
+ PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
break;\r
case EfiBootServicesCode:\r
case EfiLoaderCode:\r
}\r
\r
/**\r
- Protect or unprotect UEFI image common function.\r
+ Protect UEFI PE/COFF image.\r
\r
@param[in] LoadedImage The loaded image protocol\r
@param[in] LoadedImageDevicePath The loaded image device path protocol\r
- @param[in] Protect TRUE: Protect the UEFI image.\r
- FALSE: Unprotect the UEFI image.\r
**/\r
VOID\r
-ProtectUefiImageCommon (\r
+ProtectUefiImage (\r
IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath,\r
- IN BOOLEAN Protect\r
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
)\r
{\r
VOID *ImageAddress;\r
}\r
\r
if (ImageRecord->CodeSegmentCount == 0) {\r
- DEBUG ((DEBUG_ERROR, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));\r
+ //\r
+ // If a UEFI executable consists of a single read+write+exec PE/COFF\r
+ // section, that isn't actually an error. The image can be launched\r
+ // alright, only image protection cannot be applied to it fully.\r
+ //\r
+ // One example that elicits this is (some) Linux kernels (with the EFI stub\r
+ // of course).\r
+ //\r
+ DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));\r
PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
if (PdbPointer != NULL) {\r
- DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
+ DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
}\r
goto Finish;\r
}\r
//\r
// CPU ARCH present. Update memory attribute directly.\r
//\r
- SetUefiImageProtectionAttributes (ImageRecord, Protect);\r
+ SetUefiImageProtectionAttributes (ImageRecord);\r
\r
//\r
- // Clean up\r
+ // Record the image record in the list so we can undo the protections later\r
//\r
- FreeImageRecord (ImageRecord);\r
+ InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);\r
\r
Finish:\r
return ;\r
}\r
\r
/**\r
- Protect UEFI image.\r
+ Unprotect UEFI image.\r
\r
@param[in] LoadedImage The loaded image protocol\r
@param[in] LoadedImageDevicePath The loaded image device path protocol\r
**/\r
VOID\r
-ProtectUefiImage (\r
+UnprotectUefiImage (\r
IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
)\r
{\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ LIST_ENTRY *ImageRecordLink;\r
+\r
if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
- ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, TRUE);\r
+ for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;\r
+ ImageRecordLink != &mProtectedImageRecordList;\r
+ ImageRecordLink = ImageRecordLink->ForwardLink) {\r
+ ImageRecord = CR (\r
+ ImageRecordLink,\r
+ IMAGE_PROPERTIES_RECORD,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+ );\r
+\r
+ if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {\r
+ SetUefiImageMemoryAttributes (ImageRecord->ImageBase,\r
+ ImageRecord->ImageSize,\r
+ 0);\r
+ FreeImageRecord (ImageRecord);\r
+ return;\r
+ }\r
+ }\r
}\r
}\r
\r
/**\r
- Unprotect UEFI image.\r
+ Return the EFI memory permission attribute associated with memory\r
+ type 'MemoryType' under the configured DXE memory protection policy.\r
\r
- @param[in] LoadedImage The loaded image protocol\r
- @param[in] LoadedImageDevicePath The loaded image device path protocol\r
+ @param MemoryType Memory type.\r
**/\r
+STATIC\r
+UINT64\r
+GetPermissionAttributeForMemoryType (\r
+ IN EFI_MEMORY_TYPE MemoryType\r
+ )\r
+{\r
+ UINT64 TestBit;\r
+\r
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {\r
+ TestBit = BIT63;\r
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
+ TestBit = BIT62;\r
+ } else {\r
+ TestBit = LShiftU64 (1, MemoryType);\r
+ }\r
+\r
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {\r
+ return EFI_MEMORY_XP;\r
+ } else {\r
+ return 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Sort memory map entries based upon PhysicalStart, from low to high.\r
+\r
+ @param MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
VOID\r
-UnprotectUefiImage (\r
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
+SortMemoryMap (\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ IN UINTN MemoryMapSize,\r
+ IN UINTN DescriptorSize\r
)\r
{\r
- if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
- ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, FALSE);\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;\r
+\r
+ MemoryMapEntry = MemoryMap;\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+ while (MemoryMapEntry < MemoryMapEnd) {\r
+ while (NextMemoryMapEntry < MemoryMapEnd) {\r
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ }\r
+\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+ }\r
+\r
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ }\r
+}\r
+\r
+/**\r
+ Merge adjacent memory map entries if they use the same memory protection policy\r
+\r
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
+ MemoryMap buffer. On input, this is the size of\r
+ the current memory map. On output,\r
+ it is the size of new memory map after merge.\r
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+VOID\r
+MergeMemoryMapForProtectionPolicy (\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ IN OUT UINTN *MemoryMapSize,\r
+ IN UINTN DescriptorSize\r
+ )\r
+{\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
+ UINT64 MemoryBlockLength;\r
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
+ UINT64 Attributes;\r
+\r
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);\r
+\r
+ MemoryMapEntry = MemoryMap;\r
+ NewMemoryMapEntry = MemoryMap;\r
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+\r
+ do {\r
+ MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));\r
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
+\r
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
+ Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&\r
+ ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
+ MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
+ if (NewMemoryMapEntry != MemoryMapEntry) {\r
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
+ }\r
+\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+ continue;\r
+ } else {\r
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+ break;\r
+ }\r
+ } while (TRUE);\r
+\r
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
+ }\r
+\r
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
+\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Remove exec permissions from all regions whose type is identified by\r
+ PcdDxeNxMemoryProtectionPolicy.\r
+**/\r
+STATIC\r
+VOID\r
+InitializeDxeNxMemoryProtectionPolicy (\r
+ VOID\r
+ )\r
+{\r
+ UINTN MemoryMapSize;\r
+ UINTN MapKey;\r
+ UINTN DescriptorSize;\r
+ UINT32 DescriptorVersion;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
+ EFI_STATUS Status;\r
+ UINT64 Attributes;\r
+ LIST_ENTRY *Link;\r
+ EFI_GCD_MAP_ENTRY *Entry;\r
+\r
+ //\r
+ // Get the EFI memory map.\r
+ //\r
+ MemoryMapSize = 0;\r
+ MemoryMap = NULL;\r
+\r
+ Status = gBS->GetMemoryMap (\r
+ &MemoryMapSize,\r
+ MemoryMap,\r
+ &MapKey,\r
+ &DescriptorSize,\r
+ &DescriptorVersion\r
+ );\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+ do {\r
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);\r
+ ASSERT (MemoryMap != NULL);\r
+ Status = gBS->GetMemoryMap (\r
+ &MemoryMapSize,\r
+ MemoryMap,\r
+ &MapKey,\r
+ &DescriptorSize,\r
+ &DescriptorVersion\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (MemoryMap);\r
+ }\r
+ } while (Status == EFI_BUFFER_TOO_SMALL);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG((DEBUG_ERROR, "%a: applying strict permissions to active memory regions\n",\r
+ __FUNCTION__));\r
+\r
+ MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);\r
+\r
+ MemoryMapEntry = MemoryMap;\r
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+ while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {\r
+\r
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
+ if (Attributes != 0) {\r
+ SetUefiImageMemoryAttributes (\r
+ MemoryMapEntry->PhysicalStart,\r
+ LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),\r
+ Attributes);\r
+ }\r
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ }\r
+ FreePool (MemoryMap);\r
+\r
+ //\r
+ // Apply the policy for RAM regions that we know are present and\r
+ // accessible, but have not been added to the UEFI memory map (yet).\r
+ //\r
+ if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {\r
+ DEBUG((DEBUG_ERROR,\r
+ "%a: applying strict permissions to inactive memory regions\n",\r
+ __FUNCTION__));\r
+\r
+ CoreAcquireGcdMemoryLock ();\r
+\r
+ Link = mGcdMemorySpaceMap.ForwardLink;\r
+ while (Link != &mGcdMemorySpaceMap) {\r
+\r
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
+\r
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
+ Entry->EndAddress < MAX_ADDRESS &&\r
+ (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
+\r
+ Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |\r
+ (Entry->Attributes & CACHE_ATTRIBUTE_MASK);\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",\r
+ Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,\r
+ Attributes));\r
+\r
+ ASSERT(gCpu != NULL);\r
+ gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,\r
+ Entry->EndAddress - Entry->BaseAddress + 1, Attributes);\r
+ }\r
+\r
+ Link = Link->ForwardLink;\r
+ }\r
+ CoreReleaseGcdMemoryLock ();\r
}\r
}\r
\r
+\r
/**\r
A notification for CPU_ARCH protocol.\r
\r
return;\r
}\r
\r
+ //\r
+ // Apply the memory protection policy on non-BScode/RTcode regions.\r
+ //\r
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
+ InitializeDxeNxMemoryProtectionPolicy ();\r
+ }\r
+\r
+ if (mImageProtectionPolicy == 0) {\r
+ return;\r
+ }\r
+\r
Status = gBS->LocateHandleBuffer (\r
ByProtocol,\r
&gEfiLoadedImageProtocolGuid,\r
}\r
}\r
\r
+/**\r
+ Disable NULL pointer detection after EndOfDxe. This is a workaround resort in\r
+ order to skip unfixable NULL pointer access issues detected in OptionROM or\r
+ boot loaders.\r
+\r
+ @param[in] Event The Event this notify function registered to.\r
+ @param[in] Context Pointer to the context data registered to the Event.\r
+**/\r
+VOID\r
+EFIAPI\r
+DisableNullDetectionAtTheEndOfDxe (\r
+ EFI_EVENT Event,\r
+ VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;\r
+\r
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));\r
+ //\r
+ // Disable NULL pointer detection by enabling first 4K page\r
+ //\r
+ Status = CoreGetMemorySpaceDescriptor (0, &Desc);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {\r
+ Status = CoreSetMemorySpaceCapabilities (\r
+ 0,\r
+ EFI_PAGE_SIZE,\r
+ Desc.Capabilities | EFI_MEMORY_RP\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ Status = CoreSetMemorySpaceAttributes (\r
+ 0,\r
+ EFI_PAGE_SIZE,\r
+ Desc.Attributes & ~EFI_MEMORY_RP\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ CoreCloseEvent (Event);\r
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));\r
+\r
+ return;\r
+}\r
+\r
/**\r
Initialize Memory Protection support.\r
**/\r
{\r
EFI_STATUS Status;\r
EFI_EVENT Event;\r
+ EFI_EVENT EndOfDxeEvent;\r
VOID *Registration;\r
\r
mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);\r
\r
- if (mImageProtectionPolicy != 0) {\r
+ InitializeListHead (&mProtectedImageRecordList);\r
+\r
+ //\r
+ // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:\r
+ // - code regions should have no EFI_MEMORY_XP attribute\r
+ // - EfiConventionalMemory and EfiBootServicesData should use the\r
+ // same attribute\r
+ // - heap guard should not be enabled for the same type of memory\r
+ //\r
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);\r
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);\r
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);\r
+ ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==\r
+ GetPermissionAttributeForMemoryType (EfiConventionalMemory));\r
+ ASSERT ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & PcdGet64 (PcdHeapGuardPoolType)) == 0);\r
+ ASSERT ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & PcdGet64 (PcdHeapGuardPageType)) == 0);\r
+\r
+ if (mImageProtectionPolicy != 0 || PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
Status = CoreCreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
TPL_CALLBACK,\r
);\r
ASSERT_EFI_ERROR(Status);\r
}\r
+\r
+ //\r
+ // Register a callback to disable NULL pointer detection at EndOfDxe\r
+ //\r
+ if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))\r
+ == (BIT0|BIT7)) {\r
+ Status = CoreCreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ DisableNullDetectionAtTheEndOfDxe,\r
+ NULL,\r
+ &gEfiEndOfDxeEventGroupGuid,\r
+ &EndOfDxeEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
return ;\r
}\r
+\r
+/**\r
+ Returns whether we are currently executing in SMM mode.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsInSmm (\r
+ VOID\r
+ )\r
+{\r
+ BOOLEAN InSmm;\r
+\r
+ InSmm = FALSE;\r
+ if (gSmmBase2 != NULL) {\r
+ gSmmBase2->InSmm (gSmmBase2, &InSmm);\r
+ }\r
+ return InSmm;\r
+}\r
+\r
+/**\r
+ Manage memory permission attributes on a memory range, according to the\r
+ configured DXE memory protection policy.\r
+\r
+ @param OldType The old memory type of the range\r
+ @param NewType The new memory type of the range\r
+ @param Memory The base address of the range\r
+ @param Length The size of the range (in bytes)\r
+\r
+ @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes\r
+ are updated in this case\r
+ @return EFI_SUCCESS If the the CPU arch protocol is not installed yet\r
+ @return EFI_SUCCESS If no DXE memory protection policy has been configured\r
+ @return EFI_SUCCESS If OldType and NewType use the same permission attributes\r
+ @return other Return value of gCpu->SetMemoryAttributes()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ApplyMemoryProtectionPolicy (\r
+ IN EFI_MEMORY_TYPE OldType,\r
+ IN EFI_MEMORY_TYPE NewType,\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINT64 Length\r
+ )\r
+{\r
+ UINT64 OldAttributes;\r
+ UINT64 NewAttributes;\r
+\r
+ //\r
+ // The policy configured in PcdDxeNxMemoryProtectionPolicy\r
+ // does not apply to allocations performed in SMM mode.\r
+ //\r
+ if (IsInSmm ()) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // If the CPU arch protocol is not installed yet, we cannot manage memory\r
+ // permission attributes, and it is the job of the driver that installs this\r
+ // protocol to set the permissions on existing allocations.\r
+ //\r
+ if (gCpu == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Check if a DXE memory protection policy has been configured\r
+ //\r
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Update the executable permissions according to the DXE memory\r
+ // protection policy, but only if\r
+ // - the policy is different between the old and the new type, or\r
+ // - this is a newly added region (OldType == EfiMaxMemoryType)\r
+ //\r
+ NewAttributes = GetPermissionAttributeForMemoryType (NewType);\r
+\r
+ if (OldType != EfiMaxMemoryType) {\r
+ OldAttributes = GetPermissionAttributeForMemoryType (OldType);\r
+ if (OldAttributes == NewAttributes) {\r
+ // policy is the same between OldType and NewType\r
+ return EFI_SUCCESS;\r
+ }\r
+ } else if (NewAttributes == 0) {\r
+ // newly added region of a type that does not require protection\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);\r
+}\r