]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
c43e0d08ae7caa72695dc43fdf356c86a2d6fbb7
[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 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/SimpleFileSystem.h>
48
49 #include "DxeMain.h"
50 #include "Mem/HeapGuard.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 BOOLEAN IsAligned;
410 UINT32 ProtectionPolicy;
411
412 DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));
413 DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));
414
415 if (gCpu == NULL) {
416 return ;
417 }
418
419 ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);
420 switch (ProtectionPolicy) {
421 case DO_NOT_PROTECT:
422 return ;
423 case PROTECT_IF_ALIGNED_ELSE_ALLOW:
424 break;
425 default:
426 ASSERT(FALSE);
427 return ;
428 }
429
430 ImageRecord = AllocateZeroPool (sizeof(*ImageRecord));
431 if (ImageRecord == NULL) {
432 return ;
433 }
434 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
435
436 //
437 // Step 1: record whole region
438 //
439 ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase;
440 ImageRecord->ImageSize = LoadedImage->ImageSize;
441
442 ImageAddress = LoadedImage->ImageBase;
443
444 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
445 if (PdbPointer != NULL) {
446 DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
447 }
448
449 //
450 // Check PE/COFF image
451 //
452 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
453 PeCoffHeaderOffset = 0;
454 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
455 PeCoffHeaderOffset = DosHdr->e_lfanew;
456 }
457
458 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
459 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
460 DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
461 // It might be image in SMM.
462 goto Finish;
463 }
464
465 //
466 // Get SectionAlignment
467 //
468 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
469 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
470 } else {
471 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
472 }
473
474 IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType);
475 if (!IsAligned) {
476 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n",
477 SectionAlignment));
478 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
479 if (PdbPointer != NULL) {
480 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
481 }
482 goto Finish;
483 }
484
485 Section = (EFI_IMAGE_SECTION_HEADER *) (
486 (UINT8 *) (UINTN) ImageAddress +
487 PeCoffHeaderOffset +
488 sizeof(UINT32) +
489 sizeof(EFI_IMAGE_FILE_HEADER) +
490 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
491 );
492 ImageRecord->CodeSegmentCount = 0;
493 InitializeListHead (&ImageRecord->CodeSegmentList);
494 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
495 Name = Section[Index].Name;
496 DEBUG ((
497 DEBUG_VERBOSE,
498 " Section - '%c%c%c%c%c%c%c%c'\n",
499 Name[0],
500 Name[1],
501 Name[2],
502 Name[3],
503 Name[4],
504 Name[5],
505 Name[6],
506 Name[7]
507 ));
508
509 //
510 // Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE
511 // can always be mapped read-only, classify a section as a code section only
512 // if it has the executable attribute set and the writable attribute cleared.
513 //
514 // This adheres more closely to the PE/COFF spec, and avoids issues with
515 // Linux OS loaders that may consist of a single read/write/execute section.
516 //
517 if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {
518 DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
519 DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
520 DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
521 DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
522 DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
523 DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
524 DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
525 DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
526 DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
527
528 //
529 // Step 2: record code section
530 //
531 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
532 if (ImageRecordCodeSection == NULL) {
533 return ;
534 }
535 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
536
537 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
538 ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE(Section[Index].SizeOfRawData, SectionAlignment);
539
540 DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
541
542 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
543 ImageRecord->CodeSegmentCount++;
544 }
545 }
546
547 if (ImageRecord->CodeSegmentCount == 0) {
548 //
549 // If a UEFI executable consists of a single read+write+exec PE/COFF
550 // section, that isn't actually an error. The image can be launched
551 // alright, only image protection cannot be applied to it fully.
552 //
553 // One example that elicits this is (some) Linux kernels (with the EFI stub
554 // of course).
555 //
556 DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));
557 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
558 if (PdbPointer != NULL) {
559 DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
560 }
561 goto Finish;
562 }
563
564 //
565 // Final
566 //
567 SortImageRecordCodeSection (ImageRecord);
568 //
569 // Check overlap all section in ImageBase/Size
570 //
571 if (!IsImageRecordCodeSectionValid (ImageRecord)) {
572 DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
573 goto Finish;
574 }
575
576 //
577 // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
578 // Given that the loader always allocates full pages, we know the space after the image is not used.
579 //
580 ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);
581
582 //
583 // CPU ARCH present. Update memory attribute directly.
584 //
585 SetUefiImageProtectionAttributes (ImageRecord);
586
587 //
588 // Record the image record in the list so we can undo the protections later
589 //
590 InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);
591
592 Finish:
593 return ;
594 }
595
596 /**
597 Unprotect UEFI image.
598
599 @param[in] LoadedImage The loaded image protocol
600 @param[in] LoadedImageDevicePath The loaded image device path protocol
601 **/
602 VOID
603 UnprotectUefiImage (
604 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
605 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
606 )
607 {
608 IMAGE_PROPERTIES_RECORD *ImageRecord;
609 LIST_ENTRY *ImageRecordLink;
610
611 if (PcdGet32(PcdImageProtectionPolicy) != 0) {
612 for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;
613 ImageRecordLink != &mProtectedImageRecordList;
614 ImageRecordLink = ImageRecordLink->ForwardLink) {
615 ImageRecord = CR (
616 ImageRecordLink,
617 IMAGE_PROPERTIES_RECORD,
618 Link,
619 IMAGE_PROPERTIES_RECORD_SIGNATURE
620 );
621
622 if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {
623 SetUefiImageMemoryAttributes (ImageRecord->ImageBase,
624 ImageRecord->ImageSize,
625 0);
626 FreeImageRecord (ImageRecord);
627 return;
628 }
629 }
630 }
631 }
632
633 /**
634 Return the EFI memory permission attribute associated with memory
635 type 'MemoryType' under the configured DXE memory protection policy.
636
637 @param MemoryType Memory type.
638 **/
639 STATIC
640 UINT64
641 GetPermissionAttributeForMemoryType (
642 IN EFI_MEMORY_TYPE MemoryType
643 )
644 {
645 UINT64 TestBit;
646
647 if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
648 TestBit = BIT63;
649 } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
650 TestBit = BIT62;
651 } else {
652 TestBit = LShiftU64 (1, MemoryType);
653 }
654
655 if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {
656 return EFI_MEMORY_XP;
657 } else {
658 return 0;
659 }
660 }
661
662 /**
663 Sort memory map entries based upon PhysicalStart, from low to high.
664
665 @param MemoryMap A pointer to the buffer in which firmware places
666 the current memory map.
667 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
668 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
669 **/
670 STATIC
671 VOID
672 SortMemoryMap (
673 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
674 IN UINTN MemoryMapSize,
675 IN UINTN DescriptorSize
676 )
677 {
678 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
679 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
680 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
681 EFI_MEMORY_DESCRIPTOR TempMemoryMap;
682
683 MemoryMapEntry = MemoryMap;
684 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
685 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
686 while (MemoryMapEntry < MemoryMapEnd) {
687 while (NextMemoryMapEntry < MemoryMapEnd) {
688 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
689 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
690 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
691 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
692 }
693
694 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
695 }
696
697 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
698 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
699 }
700 }
701
702 /**
703 Merge adjacent memory map entries if they use the same memory protection policy
704
705 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
706 the current memory map.
707 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
708 MemoryMap buffer. On input, this is the size of
709 the current memory map. On output,
710 it is the size of new memory map after merge.
711 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
712 **/
713 STATIC
714 VOID
715 MergeMemoryMapForProtectionPolicy (
716 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
717 IN OUT UINTN *MemoryMapSize,
718 IN UINTN DescriptorSize
719 )
720 {
721 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
722 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
723 UINT64 MemoryBlockLength;
724 EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
725 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
726 UINT64 Attributes;
727
728 SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
729
730 MemoryMapEntry = MemoryMap;
731 NewMemoryMapEntry = MemoryMap;
732 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
733 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
734 CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
735 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
736
737 do {
738 MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));
739 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
740
741 if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
742 Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&
743 ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
744 MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
745 if (NewMemoryMapEntry != MemoryMapEntry) {
746 NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
747 }
748
749 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
750 continue;
751 } else {
752 MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
753 break;
754 }
755 } while (TRUE);
756
757 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
758 NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
759 }
760
761 *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
762
763 return ;
764 }
765
766
767 /**
768 Remove exec permissions from all regions whose type is identified by
769 PcdDxeNxMemoryProtectionPolicy.
770 **/
771 STATIC
772 VOID
773 InitializeDxeNxMemoryProtectionPolicy (
774 VOID
775 )
776 {
777 UINTN MemoryMapSize;
778 UINTN MapKey;
779 UINTN DescriptorSize;
780 UINT32 DescriptorVersion;
781 EFI_MEMORY_DESCRIPTOR *MemoryMap;
782 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
783 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
784 EFI_STATUS Status;
785 UINT64 Attributes;
786 LIST_ENTRY *Link;
787 EFI_GCD_MAP_ENTRY *Entry;
788 EFI_PEI_HOB_POINTERS Hob;
789 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
790 EFI_PHYSICAL_ADDRESS StackBase;
791
792 //
793 // Get the EFI memory map.
794 //
795 MemoryMapSize = 0;
796 MemoryMap = NULL;
797
798 Status = gBS->GetMemoryMap (
799 &MemoryMapSize,
800 MemoryMap,
801 &MapKey,
802 &DescriptorSize,
803 &DescriptorVersion
804 );
805 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
806 do {
807 MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
808 ASSERT (MemoryMap != NULL);
809 Status = gBS->GetMemoryMap (
810 &MemoryMapSize,
811 MemoryMap,
812 &MapKey,
813 &DescriptorSize,
814 &DescriptorVersion
815 );
816 if (EFI_ERROR (Status)) {
817 FreePool (MemoryMap);
818 }
819 } while (Status == EFI_BUFFER_TOO_SMALL);
820 ASSERT_EFI_ERROR (Status);
821
822 StackBase = 0;
823 if (PcdGetBool (PcdCpuStackGuard)) {
824 //
825 // Get the base of stack from Hob.
826 //
827 Hob.Raw = GetHobList ();
828 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
829 MemoryHob = Hob.MemoryAllocation;
830 if (CompareGuid(&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {
831 DEBUG ((
832 DEBUG_INFO,
833 "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",
834 __FUNCTION__,
835 MemoryHob->AllocDescriptor.MemoryBaseAddress,
836 MemoryHob->AllocDescriptor.MemoryLength
837 ));
838
839 StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;
840 //
841 // Ensure the base of the stack is page-size aligned.
842 //
843 ASSERT ((StackBase & EFI_PAGE_MASK) == 0);
844 break;
845 }
846 Hob.Raw = GET_NEXT_HOB (Hob);
847 }
848
849 //
850 // Ensure the base of stack can be found from Hob when stack guard is
851 // enabled.
852 //
853 ASSERT (StackBase != 0);
854 }
855
856 DEBUG ((
857 DEBUG_INFO,
858 "%a: applying strict permissions to active memory regions\n",
859 __FUNCTION__
860 ));
861
862 MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);
863
864 MemoryMapEntry = MemoryMap;
865 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
866 while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
867
868 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
869 if (Attributes != 0) {
870 SetUefiImageMemoryAttributes (
871 MemoryMapEntry->PhysicalStart,
872 LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),
873 Attributes);
874
875 //
876 // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is
877 // enabled.
878 //
879 if (MemoryMapEntry->PhysicalStart == 0 &&
880 PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0) {
881
882 ASSERT (MemoryMapEntry->NumberOfPages > 0);
883 SetUefiImageMemoryAttributes (
884 0,
885 EFI_PAGES_TO_SIZE (1),
886 EFI_MEMORY_RP | Attributes);
887 }
888
889 //
890 // Add EFI_MEMORY_RP attribute for the first page of the stack if stack
891 // guard is enabled.
892 //
893 if (StackBase != 0 &&
894 (StackBase >= MemoryMapEntry->PhysicalStart &&
895 StackBase < MemoryMapEntry->PhysicalStart +
896 LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT)) &&
897 PcdGetBool (PcdCpuStackGuard)) {
898
899 SetUefiImageMemoryAttributes (
900 StackBase,
901 EFI_PAGES_TO_SIZE (1),
902 EFI_MEMORY_RP | Attributes);
903 }
904
905 }
906 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
907 }
908 FreePool (MemoryMap);
909
910 //
911 // Apply the policy for RAM regions that we know are present and
912 // accessible, but have not been added to the UEFI memory map (yet).
913 //
914 if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {
915 DEBUG ((
916 DEBUG_INFO,
917 "%a: applying strict permissions to inactive memory regions\n",
918 __FUNCTION__
919 ));
920
921 CoreAcquireGcdMemoryLock ();
922
923 Link = mGcdMemorySpaceMap.ForwardLink;
924 while (Link != &mGcdMemorySpaceMap) {
925
926 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
927
928 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
929 Entry->EndAddress < MAX_ADDRESS &&
930 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
931 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
932
933 Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
934 (Entry->Attributes & CACHE_ATTRIBUTE_MASK);
935
936 DEBUG ((DEBUG_INFO,
937 "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
938 Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,
939 Attributes));
940
941 ASSERT(gCpu != NULL);
942 gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,
943 Entry->EndAddress - Entry->BaseAddress + 1, Attributes);
944 }
945
946 Link = Link->ForwardLink;
947 }
948 CoreReleaseGcdMemoryLock ();
949 }
950 }
951
952
953 /**
954 A notification for CPU_ARCH protocol.
955
956 @param[in] Event Event whose notification function is being invoked.
957 @param[in] Context Pointer to the notification function's context,
958 which is implementation-dependent.
959
960 **/
961 VOID
962 EFIAPI
963 MemoryProtectionCpuArchProtocolNotify (
964 IN EFI_EVENT Event,
965 IN VOID *Context
966 )
967 {
968 EFI_STATUS Status;
969 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
970 EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
971 UINTN NoHandles;
972 EFI_HANDLE *HandleBuffer;
973 UINTN Index;
974
975 DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));
976 Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
977 if (EFI_ERROR (Status)) {
978 goto Done;
979 }
980
981 //
982 // Apply the memory protection policy on non-BScode/RTcode regions.
983 //
984 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {
985 InitializeDxeNxMemoryProtectionPolicy ();
986 }
987
988 //
989 // Call notify function meant for Heap Guard.
990 //
991 HeapGuardCpuArchProtocolNotify ();
992
993 if (mImageProtectionPolicy == 0) {
994 goto Done;
995 }
996
997 Status = gBS->LocateHandleBuffer (
998 ByProtocol,
999 &gEfiLoadedImageProtocolGuid,
1000 NULL,
1001 &NoHandles,
1002 &HandleBuffer
1003 );
1004 if (EFI_ERROR (Status) && (NoHandles == 0)) {
1005 goto Done;
1006 }
1007
1008 for (Index = 0; Index < NoHandles; Index++) {
1009 Status = gBS->HandleProtocol (
1010 HandleBuffer[Index],
1011 &gEfiLoadedImageProtocolGuid,
1012 (VOID **)&LoadedImage
1013 );
1014 if (EFI_ERROR(Status)) {
1015 continue;
1016 }
1017 Status = gBS->HandleProtocol (
1018 HandleBuffer[Index],
1019 &gEfiLoadedImageDevicePathProtocolGuid,
1020 (VOID **)&LoadedImageDevicePath
1021 );
1022 if (EFI_ERROR(Status)) {
1023 LoadedImageDevicePath = NULL;
1024 }
1025
1026 ProtectUefiImage (LoadedImage, LoadedImageDevicePath);
1027 }
1028 FreePool (HandleBuffer);
1029
1030 Done:
1031 CoreCloseEvent (Event);
1032 }
1033
1034 /**
1035 ExitBootServices Callback function for memory protection.
1036 **/
1037 VOID
1038 MemoryProtectionExitBootServicesCallback (
1039 VOID
1040 )
1041 {
1042 EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
1043 LIST_ENTRY *Link;
1044
1045 //
1046 // We need remove the RT protection, because RT relocation need write code segment
1047 // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.
1048 //
1049 // Firmware does not own page tables after ExitBootServices(), so the OS would
1050 // have to relax protection of RT code pages across SetVirtualAddressMap(), or
1051 // delay setting protections on RT code pages until after SetVirtualAddressMap().
1052 // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.
1053 //
1054 if (mImageProtectionPolicy != 0) {
1055 for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {
1056 RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
1057 SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);
1058 }
1059 }
1060 }
1061
1062 /**
1063 Disable NULL pointer detection after EndOfDxe. This is a workaround resort in
1064 order to skip unfixable NULL pointer access issues detected in OptionROM or
1065 boot loaders.
1066
1067 @param[in] Event The Event this notify function registered to.
1068 @param[in] Context Pointer to the context data registered to the Event.
1069 **/
1070 VOID
1071 EFIAPI
1072 DisableNullDetectionAtTheEndOfDxe (
1073 EFI_EVENT Event,
1074 VOID *Context
1075 )
1076 {
1077 EFI_STATUS Status;
1078 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
1079
1080 DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));
1081 //
1082 // Disable NULL pointer detection by enabling first 4K page
1083 //
1084 Status = CoreGetMemorySpaceDescriptor (0, &Desc);
1085 ASSERT_EFI_ERROR (Status);
1086
1087 if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
1088 Status = CoreSetMemorySpaceCapabilities (
1089 0,
1090 EFI_PAGE_SIZE,
1091 Desc.Capabilities | EFI_MEMORY_RP
1092 );
1093 ASSERT_EFI_ERROR (Status);
1094 }
1095
1096 Status = CoreSetMemorySpaceAttributes (
1097 0,
1098 EFI_PAGE_SIZE,
1099 Desc.Attributes & ~EFI_MEMORY_RP
1100 );
1101 ASSERT_EFI_ERROR (Status);
1102
1103 CoreCloseEvent (Event);
1104 DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));
1105
1106 return;
1107 }
1108
1109 /**
1110 Initialize Memory Protection support.
1111 **/
1112 VOID
1113 EFIAPI
1114 CoreInitializeMemoryProtection (
1115 VOID
1116 )
1117 {
1118 EFI_STATUS Status;
1119 EFI_EVENT Event;
1120 EFI_EVENT EndOfDxeEvent;
1121 VOID *Registration;
1122
1123 mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);
1124
1125 InitializeListHead (&mProtectedImageRecordList);
1126
1127 //
1128 // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:
1129 // - code regions should have no EFI_MEMORY_XP attribute
1130 // - EfiConventionalMemory and EfiBootServicesData should use the
1131 // same attribute
1132 //
1133 ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);
1134 ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);
1135 ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);
1136 ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==
1137 GetPermissionAttributeForMemoryType (EfiConventionalMemory));
1138
1139 Status = CoreCreateEvent (
1140 EVT_NOTIFY_SIGNAL,
1141 TPL_CALLBACK,
1142 MemoryProtectionCpuArchProtocolNotify,
1143 NULL,
1144 &Event
1145 );
1146 ASSERT_EFI_ERROR(Status);
1147
1148 //
1149 // Register for protocol notifactions on this event
1150 //
1151 Status = CoreRegisterProtocolNotify (
1152 &gEfiCpuArchProtocolGuid,
1153 Event,
1154 &Registration
1155 );
1156 ASSERT_EFI_ERROR(Status);
1157
1158 //
1159 // Register a callback to disable NULL pointer detection at EndOfDxe
1160 //
1161 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))
1162 == (BIT0|BIT7)) {
1163 Status = CoreCreateEventEx (
1164 EVT_NOTIFY_SIGNAL,
1165 TPL_NOTIFY,
1166 DisableNullDetectionAtTheEndOfDxe,
1167 NULL,
1168 &gEfiEndOfDxeEventGroupGuid,
1169 &EndOfDxeEvent
1170 );
1171 ASSERT_EFI_ERROR (Status);
1172 }
1173
1174 return ;
1175 }
1176
1177 /**
1178 Returns whether we are currently executing in SMM mode.
1179 **/
1180 STATIC
1181 BOOLEAN
1182 IsInSmm (
1183 VOID
1184 )
1185 {
1186 BOOLEAN InSmm;
1187
1188 InSmm = FALSE;
1189 if (gSmmBase2 != NULL) {
1190 gSmmBase2->InSmm (gSmmBase2, &InSmm);
1191 }
1192 return InSmm;
1193 }
1194
1195 /**
1196 Manage memory permission attributes on a memory range, according to the
1197 configured DXE memory protection policy.
1198
1199 @param OldType The old memory type of the range
1200 @param NewType The new memory type of the range
1201 @param Memory The base address of the range
1202 @param Length The size of the range (in bytes)
1203
1204 @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes
1205 are updated in this case
1206 @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
1207 @return EFI_SUCCESS If no DXE memory protection policy has been configured
1208 @return EFI_SUCCESS If OldType and NewType use the same permission attributes
1209 @return other Return value of gCpu->SetMemoryAttributes()
1210
1211 **/
1212 EFI_STATUS
1213 EFIAPI
1214 ApplyMemoryProtectionPolicy (
1215 IN EFI_MEMORY_TYPE OldType,
1216 IN EFI_MEMORY_TYPE NewType,
1217 IN EFI_PHYSICAL_ADDRESS Memory,
1218 IN UINT64 Length
1219 )
1220 {
1221 UINT64 OldAttributes;
1222 UINT64 NewAttributes;
1223
1224 //
1225 // The policy configured in PcdDxeNxMemoryProtectionPolicy
1226 // does not apply to allocations performed in SMM mode.
1227 //
1228 if (IsInSmm ()) {
1229 return EFI_SUCCESS;
1230 }
1231
1232 //
1233 // If the CPU arch protocol is not installed yet, we cannot manage memory
1234 // permission attributes, and it is the job of the driver that installs this
1235 // protocol to set the permissions on existing allocations.
1236 //
1237 if (gCpu == NULL) {
1238 return EFI_SUCCESS;
1239 }
1240
1241 //
1242 // Check if a DXE memory protection policy has been configured
1243 //
1244 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {
1245 return EFI_SUCCESS;
1246 }
1247
1248 //
1249 // Don't overwrite Guard pages, which should be the first and/or last page,
1250 // if any.
1251 //
1252 if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
1253 if (IsGuardPage (Memory)) {
1254 Memory += EFI_PAGE_SIZE;
1255 Length -= EFI_PAGE_SIZE;
1256 if (Length == 0) {
1257 return EFI_SUCCESS;
1258 }
1259 }
1260
1261 if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {
1262 Length -= EFI_PAGE_SIZE;
1263 if (Length == 0) {
1264 return EFI_SUCCESS;
1265 }
1266 }
1267 }
1268
1269 //
1270 // Update the executable permissions according to the DXE memory
1271 // protection policy, but only if
1272 // - the policy is different between the old and the new type, or
1273 // - this is a newly added region (OldType == EfiMaxMemoryType)
1274 //
1275 NewAttributes = GetPermissionAttributeForMemoryType (NewType);
1276
1277 if (OldType != EfiMaxMemoryType) {
1278 OldAttributes = GetPermissionAttributeForMemoryType (OldType);
1279 if (OldAttributes == NewAttributes) {
1280 // policy is the same between OldType and NewType
1281 return EFI_SUCCESS;
1282 }
1283 } else if (NewAttributes == 0) {
1284 // newly added region of a type that does not require protection
1285 return EFI_SUCCESS;
1286 }
1287
1288 return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);
1289 }