]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
MdeModulePkg/Core: allow HeapGuard even before CpuArchProtocol installed
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / MemoryProtection.c
CommitLineData
d0e92aad
JY
1/** @file\r
2 UEFI Memory Protection support.\r
3\r
4 If the UEFI image is page aligned, the image code section is set to read only\r
5 and the image data section is set to non-executable.\r
6\r
7 1) This policy is applied for all UEFI image including boot service driver,\r
8 runtime driver or application.\r
9 2) This policy is applied only if the UEFI image meets the page alignment\r
10 requirement.\r
11 3) This policy is applied only if the Source UEFI image matches the\r
12 PcdImageProtectionPolicy definition.\r
13 4) This policy is not applied to the non-PE image region.\r
14\r
15 The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect\r
16 the image. If the CpuArch protocol is not installed yet, the DxeCore\r
17 enqueues the protection request. Once the CpuArch is installed, the\r
18 DxeCore dequeues the protection request and applies policy.\r
19\r
20 Once the image is unloaded, the protection is removed automatically.\r
21\r
a10acf0e 22Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>\r
d0e92aad
JY
23This program and the accompanying materials\r
24are licensed and made available under the terms and conditions of the BSD License\r
25which accompanies this distribution. The full text of the license may be found at\r
26http://opensource.org/licenses/bsd-license.php\r
27\r
28THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
29WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
30\r
31**/\r
32\r
33#include <PiDxe.h>\r
34#include <Library/BaseLib.h>\r
35#include <Library/BaseMemoryLib.h>\r
36#include <Library/MemoryAllocationLib.h>\r
37#include <Library/UefiBootServicesTableLib.h>\r
38#include <Library/DxeServicesTableLib.h>\r
39#include <Library/DebugLib.h>\r
40#include <Library/UefiLib.h>\r
41\r
42#include <Guid/EventGroup.h>\r
43#include <Guid/MemoryAttributesTable.h>\r
44#include <Guid/PropertiesTable.h>\r
45\r
46#include <Protocol/FirmwareVolume2.h>\r
47#include <Protocol/BlockIo.h>\r
48#include <Protocol/SimpleFileSystem.h>\r
49\r
50#include "DxeMain.h"\r
a6a0a597 51#include "Mem/HeapGuard.h"\r
d0e92aad
JY
52\r
53#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP)\r
54#define MEMORY_ATTRIBUTE_MASK (EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RO)\r
55\r
56//\r
57// Image type definitions\r
58//\r
59#define IMAGE_UNKNOWN 0x00000001\r
60#define IMAGE_FROM_FV 0x00000002\r
61\r
62//\r
63// Protection policy bit definition\r
64//\r
65#define DO_NOT_PROTECT 0x00000000\r
66#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001\r
67\r
7eb927db
AB
68#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000\r
69#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000\r
70\r
71#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
72 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
73\r
d0e92aad
JY
74UINT32 mImageProtectionPolicy;\r
75\r
7eb927db
AB
76extern LIST_ENTRY mGcdMemorySpaceMap;\r
77\r
5920a9d1
AB
78STATIC LIST_ENTRY mProtectedImageRecordList;\r
79\r
d0e92aad
JY
80/**\r
81 Sort code section in image record, based upon CodeSegmentBase from low to high.\r
82\r
83 @param ImageRecord image record to be sorted\r
84**/\r
85VOID\r
86SortImageRecordCodeSection (\r
87 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
88 );\r
89\r
90/**\r
91 Check if code section in image record is valid.\r
92\r
93 @param ImageRecord image record to be checked\r
94\r
95 @retval TRUE image record is valid\r
96 @retval FALSE image record is invalid\r
97**/\r
98BOOLEAN\r
99IsImageRecordCodeSectionValid (\r
100 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
101 );\r
102\r
103/**\r
104 Get the image type.\r
105\r
106 @param[in] File This is a pointer to the device path of the file that is\r
107 being dispatched.\r
108\r
109 @return UINT32 Image Type\r
110**/\r
111UINT32\r
112GetImageType (\r
113 IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
114 )\r
115{\r
116 EFI_STATUS Status;\r
117 EFI_HANDLE DeviceHandle;\r
118 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
119\r
120 if (File == NULL) {\r
121 return IMAGE_UNKNOWN;\r
122 }\r
123\r
124 //\r
125 // First check to see if File is from a Firmware Volume\r
126 //\r
127 DeviceHandle = NULL;\r
128 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
129 Status = gBS->LocateDevicePath (\r
130 &gEfiFirmwareVolume2ProtocolGuid,\r
131 &TempDevicePath,\r
132 &DeviceHandle\r
133 );\r
134 if (!EFI_ERROR (Status)) {\r
135 Status = gBS->OpenProtocol (\r
136 DeviceHandle,\r
137 &gEfiFirmwareVolume2ProtocolGuid,\r
138 NULL,\r
139 NULL,\r
140 NULL,\r
141 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
142 );\r
143 if (!EFI_ERROR (Status)) {\r
144 return IMAGE_FROM_FV;\r
145 }\r
146 }\r
147 return IMAGE_UNKNOWN;\r
148}\r
149\r
150/**\r
151 Get UEFI image protection policy based upon image type.\r
152\r
153 @param[in] ImageType The UEFI image type\r
154\r
155 @return UEFI image protection policy\r
156**/\r
157UINT32\r
158GetProtectionPolicyFromImageType (\r
159 IN UINT32 ImageType\r
160 )\r
161{\r
162 if ((ImageType & mImageProtectionPolicy) == 0) {\r
163 return DO_NOT_PROTECT;\r
164 } else {\r
165 return PROTECT_IF_ALIGNED_ELSE_ALLOW;\r
166 }\r
167}\r
168\r
169/**\r
170 Get UEFI image protection policy based upon loaded image device path.\r
171\r
172 @param[in] LoadedImage The loaded image protocol\r
173 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
174\r
175 @return UEFI image protection policy\r
176**/\r
177UINT32\r
178GetUefiImageProtectionPolicy (\r
179 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
180 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
181 )\r
182{\r
183 BOOLEAN InSmm;\r
184 UINT32 ImageType;\r
185 UINT32 ProtectionPolicy;\r
186\r
187 //\r
188 // Check SMM\r
189 //\r
190 InSmm = FALSE;\r
191 if (gSmmBase2 != NULL) {\r
192 gSmmBase2->InSmm (gSmmBase2, &InSmm);\r
193 }\r
194 if (InSmm) {\r
195 return FALSE;\r
196 }\r
197\r
198 //\r
199 // Check DevicePath\r
200 //\r
201 if (LoadedImage == gDxeCoreLoadedImage) {\r
202 ImageType = IMAGE_FROM_FV;\r
203 } else {\r
204 ImageType = GetImageType (LoadedImageDevicePath);\r
205 }\r
206 ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);\r
207 return ProtectionPolicy;\r
208}\r
209\r
210\r
211/**\r
212 Set UEFI image memory attributes.\r
213\r
214 @param[in] BaseAddress Specified start address\r
215 @param[in] Length Specified length\r
216 @param[in] Attributes Specified attributes\r
217**/\r
218VOID\r
219SetUefiImageMemoryAttributes (\r
220 IN UINT64 BaseAddress,\r
221 IN UINT64 Length,\r
222 IN UINT64 Attributes\r
223 )\r
224{\r
225 EFI_STATUS Status;\r
226 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
227 UINT64 FinalAttributes;\r
228\r
229 Status = CoreGetMemorySpaceDescriptor(BaseAddress, &Descriptor);\r
230 ASSERT_EFI_ERROR(Status);\r
231\r
232 FinalAttributes = (Descriptor.Attributes & CACHE_ATTRIBUTE_MASK) | (Attributes & MEMORY_ATTRIBUTE_MASK);\r
233\r
234 DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));\r
235\r
236 ASSERT(gCpu != NULL);\r
237 gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);\r
238}\r
239\r
240/**\r
241 Set UEFI image protection attributes.\r
242\r
243 @param[in] ImageRecord A UEFI image record\r
d0e92aad
JY
244**/\r
245VOID\r
246SetUefiImageProtectionAttributes (\r
5920a9d1 247 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
d0e92aad
JY
248 )\r
249{\r
250 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
251 LIST_ENTRY *ImageRecordCodeSectionLink;\r
252 LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
253 LIST_ENTRY *ImageRecordCodeSectionList;\r
254 UINT64 CurrentBase;\r
255 UINT64 ImageEnd;\r
d0e92aad
JY
256\r
257 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
258\r
259 CurrentBase = ImageRecord->ImageBase;\r
260 ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
261\r
262 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
263 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
264 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
265 ImageRecordCodeSection = CR (\r
266 ImageRecordCodeSectionLink,\r
267 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
268 Link,\r
269 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
270 );\r
271 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
272\r
273 ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);\r
274 if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {\r
275 //\r
276 // DATA\r
277 //\r
d0e92aad
JY
278 SetUefiImageMemoryAttributes (\r
279 CurrentBase,\r
280 ImageRecordCodeSection->CodeSegmentBase - CurrentBase,\r
5920a9d1 281 EFI_MEMORY_XP\r
d0e92aad
JY
282 );\r
283 }\r
284 //\r
285 // CODE\r
286 //\r
d0e92aad
JY
287 SetUefiImageMemoryAttributes (\r
288 ImageRecordCodeSection->CodeSegmentBase,\r
289 ImageRecordCodeSection->CodeSegmentSize,\r
5920a9d1 290 EFI_MEMORY_RO\r
d0e92aad
JY
291 );\r
292 CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;\r
293 }\r
294 //\r
295 // Last DATA\r
296 //\r
297 ASSERT (CurrentBase <= ImageEnd);\r
298 if (CurrentBase < ImageEnd) {\r
299 //\r
300 // DATA\r
301 //\r
d0e92aad
JY
302 SetUefiImageMemoryAttributes (\r
303 CurrentBase,\r
304 ImageEnd - CurrentBase,\r
5920a9d1 305 EFI_MEMORY_XP\r
d0e92aad
JY
306 );\r
307 }\r
308 return ;\r
309}\r
310\r
311/**\r
312 Return if the PE image section is aligned.\r
313\r
314 @param[in] SectionAlignment PE/COFF section alignment\r
315 @param[in] MemoryType PE/COFF image memory type\r
316\r
317 @retval TRUE The PE image section is aligned.\r
318 @retval FALSE The PE image section is not aligned.\r
319**/\r
320BOOLEAN\r
321IsMemoryProtectionSectionAligned (\r
322 IN UINT32 SectionAlignment,\r
323 IN EFI_MEMORY_TYPE MemoryType\r
324 )\r
325{\r
326 UINT32 PageAlignment;\r
327\r
328 switch (MemoryType) {\r
329 case EfiRuntimeServicesCode:\r
330 case EfiACPIMemoryNVS:\r
d4731a98 331 PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
d0e92aad
JY
332 break;\r
333 case EfiRuntimeServicesData:\r
334 case EfiACPIReclaimMemory:\r
335 ASSERT (FALSE);\r
d4731a98 336 PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
d0e92aad
JY
337 break;\r
338 case EfiBootServicesCode:\r
339 case EfiLoaderCode:\r
340 case EfiReservedMemoryType:\r
341 PageAlignment = EFI_PAGE_SIZE;\r
342 break;\r
343 default:\r
344 ASSERT (FALSE);\r
345 PageAlignment = EFI_PAGE_SIZE;\r
346 break;\r
347 }\r
348\r
349 if ((SectionAlignment & (PageAlignment - 1)) != 0) {\r
350 return FALSE;\r
351 } else {\r
352 return TRUE;\r
353 }\r
354}\r
355\r
356/**\r
357 Free Image record.\r
358\r
359 @param[in] ImageRecord A UEFI image record\r
360**/\r
361VOID\r
362FreeImageRecord (\r
363 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
364 )\r
365{\r
366 LIST_ENTRY *CodeSegmentListHead;\r
367 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
368\r
369 CodeSegmentListHead = &ImageRecord->CodeSegmentList;\r
370 while (!IsListEmpty (CodeSegmentListHead)) {\r
371 ImageRecordCodeSection = CR (\r
372 CodeSegmentListHead->ForwardLink,\r
373 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
374 Link,\r
375 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
376 );\r
377 RemoveEntryList (&ImageRecordCodeSection->Link);\r
378 FreePool (ImageRecordCodeSection);\r
379 }\r
380\r
381 if (ImageRecord->Link.ForwardLink != NULL) {\r
382 RemoveEntryList (&ImageRecord->Link);\r
383 }\r
384 FreePool (ImageRecord);\r
385}\r
386\r
387/**\r
13425af7 388 Protect UEFI PE/COFF image.\r
d0e92aad
JY
389\r
390 @param[in] LoadedImage The loaded image protocol\r
391 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
d0e92aad
JY
392**/\r
393VOID\r
5920a9d1 394ProtectUefiImage (\r
d0e92aad 395 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
5920a9d1 396 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
d0e92aad
JY
397 )\r
398{\r
399 VOID *ImageAddress;\r
400 EFI_IMAGE_DOS_HEADER *DosHdr;\r
401 UINT32 PeCoffHeaderOffset;\r
402 UINT32 SectionAlignment;\r
403 EFI_IMAGE_SECTION_HEADER *Section;\r
404 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
405 UINT8 *Name;\r
406 UINTN Index;\r
407 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
408 CHAR8 *PdbPointer;\r
409 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
410 UINT16 Magic;\r
411 BOOLEAN IsAligned;\r
412 UINT32 ProtectionPolicy;\r
413\r
414 DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));\r
415 DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));\r
416\r
417 if (gCpu == NULL) {\r
418 return ;\r
419 }\r
420\r
421 ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);\r
422 switch (ProtectionPolicy) {\r
423 case DO_NOT_PROTECT:\r
424 return ;\r
425 case PROTECT_IF_ALIGNED_ELSE_ALLOW:\r
426 break;\r
427 default:\r
428 ASSERT(FALSE);\r
429 return ;\r
430 }\r
431\r
432 ImageRecord = AllocateZeroPool (sizeof(*ImageRecord));\r
433 if (ImageRecord == NULL) {\r
434 return ;\r
435 }\r
436 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;\r
437\r
438 //\r
439 // Step 1: record whole region\r
440 //\r
441 ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase;\r
442 ImageRecord->ImageSize = LoadedImage->ImageSize;\r
443\r
444 ImageAddress = LoadedImage->ImageBase;\r
445\r
446 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
447 if (PdbPointer != NULL) {\r
448 DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));\r
449 }\r
450\r
451 //\r
452 // Check PE/COFF image\r
453 //\r
454 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
455 PeCoffHeaderOffset = 0;\r
456 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
457 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
458 }\r
459\r
460 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
461 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
462 DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));\r
463 // It might be image in SMM.\r
464 goto Finish;\r
465 }\r
466\r
467 //\r
468 // Get SectionAlignment\r
469 //\r
470 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
471 //\r
472 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
473 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
474 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
475 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
476 //\r
477 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
478 } else {\r
479 //\r
480 // Get the magic value from the PE/COFF Optional Header\r
481 //\r
482 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
483 }\r
484 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
485 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
486 } else {\r
487 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
488 }\r
489\r
490 IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType);\r
491 if (!IsAligned) {\r
492 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n",\r
493 SectionAlignment));\r
494 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
495 if (PdbPointer != NULL) {\r
496 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
497 }\r
498 goto Finish;\r
499 }\r
500\r
501 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
502 (UINT8 *) (UINTN) ImageAddress +\r
503 PeCoffHeaderOffset +\r
504 sizeof(UINT32) +\r
505 sizeof(EFI_IMAGE_FILE_HEADER) +\r
506 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
507 );\r
508 ImageRecord->CodeSegmentCount = 0;\r
509 InitializeListHead (&ImageRecord->CodeSegmentList);\r
510 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
511 Name = Section[Index].Name;\r
512 DEBUG ((\r
513 DEBUG_VERBOSE,\r
514 " Section - '%c%c%c%c%c%c%c%c'\n",\r
515 Name[0],\r
516 Name[1],\r
517 Name[2],\r
518 Name[3],\r
519 Name[4],\r
520 Name[5],\r
521 Name[6],\r
522 Name[7]\r
523 ));\r
524\r
a2ed40c0
AB
525 //\r
526 // Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE\r
527 // can always be mapped read-only, classify a section as a code section only\r
528 // if it has the executable attribute set and the writable attribute cleared.\r
529 //\r
530 // This adheres more closely to the PE/COFF spec, and avoids issues with\r
531 // Linux OS loaders that may consist of a single read/write/execute section.\r
532 //\r
533 if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {\r
d0e92aad
JY
534 DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));\r
535 DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));\r
536 DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));\r
537 DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));\r
538 DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));\r
539 DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));\r
540 DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));\r
541 DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));\r
542 DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));\r
543\r
544 //\r
545 // Step 2: record code section\r
546 //\r
547 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));\r
548 if (ImageRecordCodeSection == NULL) {\r
549 return ;\r
550 }\r
551 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;\r
552\r
553 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;\r
554 ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE(Section[Index].SizeOfRawData, SectionAlignment);\r
555\r
556 DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));\r
557\r
558 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);\r
559 ImageRecord->CodeSegmentCount++;\r
560 }\r
561 }\r
562\r
563 if (ImageRecord->CodeSegmentCount == 0) {\r
38b15ebe
LE
564 //\r
565 // If a UEFI executable consists of a single read+write+exec PE/COFF\r
566 // section, that isn't actually an error. The image can be launched\r
567 // alright, only image protection cannot be applied to it fully.\r
568 //\r
569 // One example that elicits this is (some) Linux kernels (with the EFI stub\r
570 // of course).\r
571 //\r
572 DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));\r
d0e92aad
JY
573 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
574 if (PdbPointer != NULL) {\r
38b15ebe 575 DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
d0e92aad
JY
576 }\r
577 goto Finish;\r
578 }\r
579\r
580 //\r
581 // Final\r
582 //\r
583 SortImageRecordCodeSection (ImageRecord);\r
584 //\r
585 // Check overlap all section in ImageBase/Size\r
586 //\r
587 if (!IsImageRecordCodeSectionValid (ImageRecord)) {\r
588 DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));\r
589 goto Finish;\r
590 }\r
591\r
592 //\r
593 // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.\r
594 // Given that the loader always allocates full pages, we know the space after the image is not used.\r
595 //\r
596 ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);\r
597\r
598 //\r
599 // CPU ARCH present. Update memory attribute directly.\r
600 //\r
5920a9d1 601 SetUefiImageProtectionAttributes (ImageRecord);\r
d0e92aad
JY
602\r
603 //\r
5920a9d1 604 // Record the image record in the list so we can undo the protections later\r
d0e92aad 605 //\r
5920a9d1 606 InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);\r
d0e92aad
JY
607\r
608Finish:\r
609 return ;\r
610}\r
611\r
d0e92aad
JY
612/**\r
613 Unprotect UEFI image.\r
614\r
615 @param[in] LoadedImage The loaded image protocol\r
616 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
617**/\r
618VOID\r
619UnprotectUefiImage (\r
620 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
621 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
622 )\r
623{\r
5920a9d1
AB
624 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
625 LIST_ENTRY *ImageRecordLink;\r
626\r
d0e92aad 627 if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
5920a9d1
AB
628 for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;\r
629 ImageRecordLink != &mProtectedImageRecordList;\r
630 ImageRecordLink = ImageRecordLink->ForwardLink) {\r
631 ImageRecord = CR (\r
632 ImageRecordLink,\r
633 IMAGE_PROPERTIES_RECORD,\r
634 Link,\r
635 IMAGE_PROPERTIES_RECORD_SIGNATURE\r
636 );\r
637\r
638 if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {\r
639 SetUefiImageMemoryAttributes (ImageRecord->ImageBase,\r
640 ImageRecord->ImageSize,\r
641 0);\r
642 FreeImageRecord (ImageRecord);\r
643 return;\r
644 }\r
645 }\r
d0e92aad
JY
646 }\r
647}\r
648\r
7eb927db
AB
649/**\r
650 Return the EFI memory permission attribute associated with memory\r
651 type 'MemoryType' under the configured DXE memory protection policy.\r
7babb437
BD
652\r
653 @param MemoryType Memory type.\r
7eb927db
AB
654**/\r
655STATIC\r
656UINT64\r
657GetPermissionAttributeForMemoryType (\r
658 IN EFI_MEMORY_TYPE MemoryType\r
659 )\r
660{\r
661 UINT64 TestBit;\r
662\r
663 if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {\r
664 TestBit = BIT63;\r
665 } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
666 TestBit = BIT62;\r
667 } else {\r
668 TestBit = LShiftU64 (1, MemoryType);\r
669 }\r
670\r
671 if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {\r
672 return EFI_MEMORY_XP;\r
673 } else {\r
674 return 0;\r
675 }\r
676}\r
677\r
678/**\r
679 Sort memory map entries based upon PhysicalStart, from low to high.\r
680\r
681 @param MemoryMap A pointer to the buffer in which firmware places\r
682 the current memory map.\r
683 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
684 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
685**/\r
686STATIC\r
687VOID\r
688SortMemoryMap (\r
689 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
690 IN UINTN MemoryMapSize,\r
691 IN UINTN DescriptorSize\r
692 )\r
693{\r
694 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
695 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
696 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
697 EFI_MEMORY_DESCRIPTOR TempMemoryMap;\r
698\r
699 MemoryMapEntry = MemoryMap;\r
700 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
701 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
702 while (MemoryMapEntry < MemoryMapEnd) {\r
703 while (NextMemoryMapEntry < MemoryMapEnd) {\r
704 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
705 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
706 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
707 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
708 }\r
709\r
710 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
711 }\r
712\r
713 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
714 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
715 }\r
716}\r
717\r
718/**\r
719 Merge adjacent memory map entries if they use the same memory protection policy\r
720\r
721 @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
722 the current memory map.\r
723 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
724 MemoryMap buffer. On input, this is the size of\r
725 the current memory map. On output,\r
726 it is the size of new memory map after merge.\r
727 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
728**/\r
729STATIC\r
730VOID\r
731MergeMemoryMapForProtectionPolicy (\r
732 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
733 IN OUT UINTN *MemoryMapSize,\r
734 IN UINTN DescriptorSize\r
735 )\r
736{\r
737 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
738 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
739 UINT64 MemoryBlockLength;\r
740 EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;\r
741 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
742 UINT64 Attributes;\r
743\r
744 SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);\r
745\r
746 MemoryMapEntry = MemoryMap;\r
747 NewMemoryMapEntry = MemoryMap;\r
748 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
749 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
750 CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
751 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
752\r
753 do {\r
754 MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));\r
755 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
756\r
757 if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
758 Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&\r
759 ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
760 MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
761 if (NewMemoryMapEntry != MemoryMapEntry) {\r
762 NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
763 }\r
764\r
765 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
766 continue;\r
767 } else {\r
768 MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
769 break;\r
770 }\r
771 } while (TRUE);\r
772\r
773 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
774 NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
775 }\r
776\r
777 *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
778\r
779 return ;\r
780}\r
781\r
782\r
783/**\r
784 Remove exec permissions from all regions whose type is identified by\r
7babb437 785 PcdDxeNxMemoryProtectionPolicy.\r
7eb927db
AB
786**/\r
787STATIC\r
788VOID\r
789InitializeDxeNxMemoryProtectionPolicy (\r
790 VOID\r
791 )\r
792{\r
793 UINTN MemoryMapSize;\r
794 UINTN MapKey;\r
795 UINTN DescriptorSize;\r
796 UINT32 DescriptorVersion;\r
797 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
798 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
799 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
800 EFI_STATUS Status;\r
801 UINT64 Attributes;\r
802 LIST_ENTRY *Link;\r
803 EFI_GCD_MAP_ENTRY *Entry;\r
7db1458f
HW
804 EFI_PEI_HOB_POINTERS Hob;\r
805 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
806 EFI_PHYSICAL_ADDRESS StackBase;\r
7eb927db
AB
807\r
808 //\r
809 // Get the EFI memory map.\r
810 //\r
811 MemoryMapSize = 0;\r
812 MemoryMap = NULL;\r
813\r
814 Status = gBS->GetMemoryMap (\r
815 &MemoryMapSize,\r
816 MemoryMap,\r
817 &MapKey,\r
818 &DescriptorSize,\r
819 &DescriptorVersion\r
820 );\r
821 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
822 do {\r
823 MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);\r
824 ASSERT (MemoryMap != NULL);\r
825 Status = gBS->GetMemoryMap (\r
826 &MemoryMapSize,\r
827 MemoryMap,\r
828 &MapKey,\r
829 &DescriptorSize,\r
830 &DescriptorVersion\r
831 );\r
832 if (EFI_ERROR (Status)) {\r
833 FreePool (MemoryMap);\r
834 }\r
835 } while (Status == EFI_BUFFER_TOO_SMALL);\r
836 ASSERT_EFI_ERROR (Status);\r
837\r
7db1458f
HW
838 StackBase = 0;\r
839 if (PcdGetBool (PcdCpuStackGuard)) {\r
840 //\r
841 // Get the base of stack from Hob.\r
842 //\r
843 Hob.Raw = GetHobList ();\r
844 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {\r
845 MemoryHob = Hob.MemoryAllocation;\r
846 if (CompareGuid(&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {\r
847 DEBUG ((\r
848 DEBUG_INFO,\r
849 "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",\r
850 __FUNCTION__,\r
851 MemoryHob->AllocDescriptor.MemoryBaseAddress,\r
852 MemoryHob->AllocDescriptor.MemoryLength\r
853 ));\r
854\r
855 StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
856 //\r
857 // Ensure the base of the stack is page-size aligned.\r
858 //\r
859 ASSERT ((StackBase & EFI_PAGE_MASK) == 0);\r
860 break;\r
861 }\r
862 Hob.Raw = GET_NEXT_HOB (Hob);\r
863 }\r
864\r
865 //\r
866 // Ensure the base of stack can be found from Hob when stack guard is\r
867 // enabled.\r
868 //\r
869 ASSERT (StackBase != 0);\r
870 }\r
871\r
a9212288
LE
872 DEBUG ((\r
873 DEBUG_INFO,\r
874 "%a: applying strict permissions to active memory regions\n",\r
875 __FUNCTION__\r
876 ));\r
7eb927db
AB
877\r
878 MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);\r
879\r
880 MemoryMapEntry = MemoryMap;\r
881 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
882 while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {\r
883\r
884 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
885 if (Attributes != 0) {\r
a10acf0e
HW
886 SetUefiImageMemoryAttributes (\r
887 MemoryMapEntry->PhysicalStart,\r
888 LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),\r
889 Attributes);\r
890\r
7db1458f
HW
891 //\r
892 // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is\r
893 // enabled.\r
894 //\r
9b17c651
JW
895 if (MemoryMapEntry->PhysicalStart == 0 &&\r
896 PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0) {\r
897\r
898 ASSERT (MemoryMapEntry->NumberOfPages > 0);\r
9b17c651 899 SetUefiImageMemoryAttributes (\r
a10acf0e
HW
900 0,\r
901 EFI_PAGES_TO_SIZE (1),\r
902 EFI_MEMORY_RP | Attributes);\r
9b17c651 903 }\r
7db1458f
HW
904\r
905 //\r
906 // Add EFI_MEMORY_RP attribute for the first page of the stack if stack\r
907 // guard is enabled.\r
908 //\r
909 if (StackBase != 0 &&\r
910 (StackBase >= MemoryMapEntry->PhysicalStart &&\r
911 StackBase < MemoryMapEntry->PhysicalStart +\r
912 LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT)) &&\r
913 PcdGetBool (PcdCpuStackGuard)) {\r
914\r
915 SetUefiImageMemoryAttributes (\r
916 StackBase,\r
917 EFI_PAGES_TO_SIZE (1),\r
918 EFI_MEMORY_RP | Attributes);\r
919 }\r
920\r
7eb927db
AB
921 }\r
922 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
923 }\r
924 FreePool (MemoryMap);\r
925\r
926 //\r
927 // Apply the policy for RAM regions that we know are present and\r
928 // accessible, but have not been added to the UEFI memory map (yet).\r
929 //\r
930 if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {\r
a9212288
LE
931 DEBUG ((\r
932 DEBUG_INFO,\r
7eb927db 933 "%a: applying strict permissions to inactive memory regions\n",\r
a9212288
LE
934 __FUNCTION__\r
935 ));\r
7eb927db
AB
936\r
937 CoreAcquireGcdMemoryLock ();\r
938\r
939 Link = mGcdMemorySpaceMap.ForwardLink;\r
940 while (Link != &mGcdMemorySpaceMap) {\r
941\r
942 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
943\r
944 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
945 Entry->EndAddress < MAX_ADDRESS &&\r
946 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
947 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
948\r
949 Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |\r
950 (Entry->Attributes & CACHE_ATTRIBUTE_MASK);\r
951\r
952 DEBUG ((DEBUG_INFO,\r
953 "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",\r
954 Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,\r
955 Attributes));\r
956\r
957 ASSERT(gCpu != NULL);\r
958 gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,\r
959 Entry->EndAddress - Entry->BaseAddress + 1, Attributes);\r
960 }\r
961\r
962 Link = Link->ForwardLink;\r
963 }\r
964 CoreReleaseGcdMemoryLock ();\r
965 }\r
966}\r
967\r
968\r
d0e92aad
JY
969/**\r
970 A notification for CPU_ARCH protocol.\r
971\r
972 @param[in] Event Event whose notification function is being invoked.\r
973 @param[in] Context Pointer to the notification function's context,\r
974 which is implementation-dependent.\r
975\r
976**/\r
977VOID\r
978EFIAPI\r
979MemoryProtectionCpuArchProtocolNotify (\r
980 IN EFI_EVENT Event,\r
981 IN VOID *Context\r
982 )\r
983{\r
984 EFI_STATUS Status;\r
985 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
986 EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;\r
987 UINTN NoHandles;\r
988 EFI_HANDLE *HandleBuffer;\r
989 UINTN Index;\r
990\r
991 DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));\r
992 Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);\r
993 if (EFI_ERROR (Status)) {\r
994 return;\r
995 }\r
996\r
7eb927db
AB
997 //\r
998 // Apply the memory protection policy on non-BScode/RTcode regions.\r
999 //\r
1000 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
1001 InitializeDxeNxMemoryProtectionPolicy ();\r
1002 }\r
1003\r
7fef06af
JW
1004 //\r
1005 // Call notify function meant for Heap Guard.\r
1006 //\r
1007 HeapGuardCpuArchProtocolNotify ();\r
1008\r
7eb927db
AB
1009 if (mImageProtectionPolicy == 0) {\r
1010 return;\r
1011 }\r
1012\r
d0e92aad
JY
1013 Status = gBS->LocateHandleBuffer (\r
1014 ByProtocol,\r
1015 &gEfiLoadedImageProtocolGuid,\r
1016 NULL,\r
1017 &NoHandles,\r
1018 &HandleBuffer\r
1019 );\r
1020 if (EFI_ERROR (Status) && (NoHandles == 0)) {\r
1021 return ;\r
1022 }\r
1023\r
1024 for (Index = 0; Index < NoHandles; Index++) {\r
1025 Status = gBS->HandleProtocol (\r
1026 HandleBuffer[Index],\r
1027 &gEfiLoadedImageProtocolGuid,\r
1028 (VOID **)&LoadedImage\r
1029 );\r
1030 if (EFI_ERROR(Status)) {\r
1031 continue;\r
1032 }\r
1033 Status = gBS->HandleProtocol (\r
1034 HandleBuffer[Index],\r
1035 &gEfiLoadedImageDevicePathProtocolGuid,\r
1036 (VOID **)&LoadedImageDevicePath\r
1037 );\r
1038 if (EFI_ERROR(Status)) {\r
1039 LoadedImageDevicePath = NULL;\r
1040 }\r
1041\r
1042 ProtectUefiImage (LoadedImage, LoadedImageDevicePath);\r
1043 }\r
1044\r
1045 CoreCloseEvent (Event);\r
1046 return;\r
1047}\r
1048\r
1049/**\r
1050 ExitBootServices Callback function for memory protection.\r
1051**/\r
1052VOID\r
1053MemoryProtectionExitBootServicesCallback (\r
1054 VOID\r
1055 )\r
1056{\r
1057 EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;\r
1058 LIST_ENTRY *Link;\r
1059\r
1060 //\r
1061 // We need remove the RT protection, because RT relocation need write code segment\r
1062 // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.\r
1063 //\r
1064 // Firmware does not own page tables after ExitBootServices(), so the OS would\r
1065 // have to relax protection of RT code pages across SetVirtualAddressMap(), or\r
1066 // delay setting protections on RT code pages until after SetVirtualAddressMap().\r
1067 // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.\r
1068 //\r
1069 if (mImageProtectionPolicy != 0) {\r
1070 for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {\r
1071 RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);\r
1072 SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);\r
1073 }\r
1074 }\r
1075}\r
1076\r
a7181d95
JW
1077/**\r
1078 Disable NULL pointer detection after EndOfDxe. This is a workaround resort in\r
1079 order to skip unfixable NULL pointer access issues detected in OptionROM or\r
1080 boot loaders.\r
1081\r
1082 @param[in] Event The Event this notify function registered to.\r
1083 @param[in] Context Pointer to the context data registered to the Event.\r
1084**/\r
1085VOID\r
1086EFIAPI\r
1087DisableNullDetectionAtTheEndOfDxe (\r
1088 EFI_EVENT Event,\r
1089 VOID *Context\r
1090 )\r
1091{\r
1092 EFI_STATUS Status;\r
1093 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;\r
1094\r
1095 DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));\r
1096 //\r
1097 // Disable NULL pointer detection by enabling first 4K page\r
1098 //\r
1099 Status = CoreGetMemorySpaceDescriptor (0, &Desc);\r
1100 ASSERT_EFI_ERROR (Status);\r
1101\r
1102 if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {\r
1103 Status = CoreSetMemorySpaceCapabilities (\r
1104 0,\r
1105 EFI_PAGE_SIZE,\r
1106 Desc.Capabilities | EFI_MEMORY_RP\r
1107 );\r
1108 ASSERT_EFI_ERROR (Status);\r
1109 }\r
1110\r
1111 Status = CoreSetMemorySpaceAttributes (\r
1112 0,\r
1113 EFI_PAGE_SIZE,\r
1114 Desc.Attributes & ~EFI_MEMORY_RP\r
1115 );\r
1116 ASSERT_EFI_ERROR (Status);\r
1117\r
1118 CoreCloseEvent (Event);\r
1119 DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));\r
1120\r
1121 return;\r
1122}\r
1123\r
d0e92aad
JY
1124/**\r
1125 Initialize Memory Protection support.\r
1126**/\r
1127VOID\r
1128EFIAPI\r
1129CoreInitializeMemoryProtection (\r
1130 VOID\r
1131 )\r
1132{\r
1133 EFI_STATUS Status;\r
1134 EFI_EVENT Event;\r
a7181d95 1135 EFI_EVENT EndOfDxeEvent;\r
d0e92aad
JY
1136 VOID *Registration;\r
1137\r
1138 mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);\r
1139\r
5920a9d1
AB
1140 InitializeListHead (&mProtectedImageRecordList);\r
1141\r
7eb927db
AB
1142 //\r
1143 // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:\r
1144 // - code regions should have no EFI_MEMORY_XP attribute\r
1145 // - EfiConventionalMemory and EfiBootServicesData should use the\r
1146 // same attribute\r
1147 //\r
1148 ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);\r
1149 ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);\r
1150 ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);\r
1151 ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==\r
1152 GetPermissionAttributeForMemoryType (EfiConventionalMemory));\r
1153\r
1154 if (mImageProtectionPolicy != 0 || PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
d0e92aad
JY
1155 Status = CoreCreateEvent (\r
1156 EVT_NOTIFY_SIGNAL,\r
1157 TPL_CALLBACK,\r
1158 MemoryProtectionCpuArchProtocolNotify,\r
1159 NULL,\r
1160 &Event\r
1161 );\r
1162 ASSERT_EFI_ERROR(Status);\r
1163\r
1164 //\r
1165 // Register for protocol notifactions on this event\r
1166 //\r
1167 Status = CoreRegisterProtocolNotify (\r
1168 &gEfiCpuArchProtocolGuid,\r
1169 Event,\r
1170 &Registration\r
1171 );\r
1172 ASSERT_EFI_ERROR(Status);\r
1173 }\r
a7181d95
JW
1174\r
1175 //\r
1176 // Register a callback to disable NULL pointer detection at EndOfDxe\r
1177 //\r
1178 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))\r
1179 == (BIT0|BIT7)) {\r
1180 Status = CoreCreateEventEx (\r
1181 EVT_NOTIFY_SIGNAL,\r
1182 TPL_NOTIFY,\r
1183 DisableNullDetectionAtTheEndOfDxe,\r
1184 NULL,\r
1185 &gEfiEndOfDxeEventGroupGuid,\r
1186 &EndOfDxeEvent\r
1187 );\r
1188 ASSERT_EFI_ERROR (Status);\r
1189 }\r
1190\r
d0e92aad
JY
1191 return ;\r
1192}\r
7eb927db
AB
1193\r
1194/**\r
7babb437 1195 Returns whether we are currently executing in SMM mode.\r
7eb927db
AB
1196**/\r
1197STATIC\r
1198BOOLEAN\r
1199IsInSmm (\r
1200 VOID\r
1201 )\r
1202{\r
1203 BOOLEAN InSmm;\r
1204\r
1205 InSmm = FALSE;\r
1206 if (gSmmBase2 != NULL) {\r
1207 gSmmBase2->InSmm (gSmmBase2, &InSmm);\r
1208 }\r
1209 return InSmm;\r
1210}\r
1211\r
1212/**\r
1213 Manage memory permission attributes on a memory range, according to the\r
1214 configured DXE memory protection policy.\r
1215\r
1216 @param OldType The old memory type of the range\r
1217 @param NewType The new memory type of the range\r
1218 @param Memory The base address of the range\r
1219 @param Length The size of the range (in bytes)\r
1220\r
1221 @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes\r
1222 are updated in this case\r
1223 @return EFI_SUCCESS If the the CPU arch protocol is not installed yet\r
1224 @return EFI_SUCCESS If no DXE memory protection policy has been configured\r
1225 @return EFI_SUCCESS If OldType and NewType use the same permission attributes\r
1226 @return other Return value of gCpu->SetMemoryAttributes()\r
1227\r
1228**/\r
1229EFI_STATUS\r
1230EFIAPI\r
1231ApplyMemoryProtectionPolicy (\r
1232 IN EFI_MEMORY_TYPE OldType,\r
1233 IN EFI_MEMORY_TYPE NewType,\r
1234 IN EFI_PHYSICAL_ADDRESS Memory,\r
1235 IN UINT64 Length\r
1236 )\r
1237{\r
1238 UINT64 OldAttributes;\r
1239 UINT64 NewAttributes;\r
1240\r
1241 //\r
1242 // The policy configured in PcdDxeNxMemoryProtectionPolicy\r
1243 // does not apply to allocations performed in SMM mode.\r
1244 //\r
1245 if (IsInSmm ()) {\r
1246 return EFI_SUCCESS;\r
1247 }\r
1248\r
1249 //\r
1250 // If the CPU arch protocol is not installed yet, we cannot manage memory\r
1251 // permission attributes, and it is the job of the driver that installs this\r
1252 // protocol to set the permissions on existing allocations.\r
1253 //\r
1254 if (gCpu == NULL) {\r
1255 return EFI_SUCCESS;\r
1256 }\r
1257\r
1258 //\r
1259 // Check if a DXE memory protection policy has been configured\r
1260 //\r
1261 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {\r
1262 return EFI_SUCCESS;\r
1263 }\r
1264\r
a6a0a597
JW
1265 //\r
1266 // Don't overwrite Guard pages, which should be the first and/or last page,\r
1267 // if any.\r
1268 //\r
1269 if (IsHeapGuardEnabled ()) {\r
1270 if (IsGuardPage (Memory)) {\r
1271 Memory += EFI_PAGE_SIZE;\r
1272 Length -= EFI_PAGE_SIZE;\r
1273 if (Length == 0) {\r
1274 return EFI_SUCCESS;\r
1275 }\r
1276 }\r
1277\r
1278 if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {\r
1279 Length -= EFI_PAGE_SIZE;\r
1280 if (Length == 0) {\r
1281 return EFI_SUCCESS;\r
1282 }\r
1283 }\r
1284 }\r
1285\r
7eb927db
AB
1286 //\r
1287 // Update the executable permissions according to the DXE memory\r
1288 // protection policy, but only if\r
1289 // - the policy is different between the old and the new type, or\r
1290 // - this is a newly added region (OldType == EfiMaxMemoryType)\r
1291 //\r
1292 NewAttributes = GetPermissionAttributeForMemoryType (NewType);\r
1293\r
1294 if (OldType != EfiMaxMemoryType) {\r
1295 OldAttributes = GetPermissionAttributeForMemoryType (OldType);\r
1296 if (OldAttributes == NewAttributes) {\r
1297 // policy is the same between OldType and NewType\r
1298 return EFI_SUCCESS;\r
1299 }\r
1300 } else if (NewAttributes == 0) {\r
1301 // newly added region of a type that does not require protection\r
1302 return EFI_SUCCESS;\r
1303 }\r
1304\r
1305 return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);\r
1306}\r