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