\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
}\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
-\r
- @param[in] LoadedImage The loaded image protocol\r
- @param[in] LoadedImageDevicePath The loaded image device path protocol\r
-**/\r
-VOID\r
-ProtectUefiImage (\r
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
- )\r
-{\r
- if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
- ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, TRUE);\r
- }\r
-}\r
-\r
/**\r
Unprotect UEFI image.\r
\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, FALSE);\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
}\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
+ 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
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);
+ ASSERT ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & PcdGet64 (PcdHeapGuardPageType)) == 0);
\r
if (mImageProtectionPolicy != 0 || PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
Status = CoreCreateEvent (\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