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