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