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