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