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