]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
MdeModulePkg/DxeCore: base code protection on permission attributes
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / MemoryProtection.c
CommitLineData
d0e92aad
JY
1/** @file\r
2 UEFI Memory Protection support.\r
3\r
4 If the UEFI image is page aligned, the image code section is set to read only\r
5 and the image data section is set to non-executable.\r
6\r
7 1) This policy is applied for all UEFI image including boot service driver,\r
8 runtime driver or application.\r
9 2) This policy is applied only if the UEFI image meets the page alignment\r
10 requirement.\r
11 3) This policy is applied only if the Source UEFI image matches the\r
12 PcdImageProtectionPolicy definition.\r
13 4) This policy is not applied to the non-PE image region.\r
14\r
15 The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect\r
16 the image. If the CpuArch protocol is not installed yet, the DxeCore\r
17 enqueues the protection request. Once the CpuArch is installed, the\r
18 DxeCore dequeues the protection request and applies policy.\r
19\r
20 Once the image is unloaded, the protection is removed automatically.\r
21\r
22Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
23This program and the accompanying materials\r
24are licensed and made available under the terms and conditions of the BSD License\r
25which accompanies this distribution. The full text of the license may be found at\r
26http://opensource.org/licenses/bsd-license.php\r
27\r
28THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
29WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
30\r
31**/\r
32\r
33#include <PiDxe.h>\r
34#include <Library/BaseLib.h>\r
35#include <Library/BaseMemoryLib.h>\r
36#include <Library/MemoryAllocationLib.h>\r
37#include <Library/UefiBootServicesTableLib.h>\r
38#include <Library/DxeServicesTableLib.h>\r
39#include <Library/DebugLib.h>\r
40#include <Library/UefiLib.h>\r
41\r
42#include <Guid/EventGroup.h>\r
43#include <Guid/MemoryAttributesTable.h>\r
44#include <Guid/PropertiesTable.h>\r
45\r
46#include <Protocol/FirmwareVolume2.h>\r
47#include <Protocol/BlockIo.h>\r
48#include <Protocol/SimpleFileSystem.h>\r
49\r
50#include "DxeMain.h"\r
51\r
52#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP)\r
53#define MEMORY_ATTRIBUTE_MASK (EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RO)\r
54\r
55//\r
56// Image type definitions\r
57//\r
58#define IMAGE_UNKNOWN 0x00000001\r
59#define IMAGE_FROM_FV 0x00000002\r
60\r
61//\r
62// Protection policy bit definition\r
63//\r
64#define DO_NOT_PROTECT 0x00000000\r
65#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001\r
66\r
67UINT32 mImageProtectionPolicy;\r
68\r
69/**\r
70 Sort code section in image record, based upon CodeSegmentBase from low to high.\r
71\r
72 @param ImageRecord image record to be sorted\r
73**/\r
74VOID\r
75SortImageRecordCodeSection (\r
76 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
77 );\r
78\r
79/**\r
80 Check if code section in image record is valid.\r
81\r
82 @param ImageRecord image record to be checked\r
83\r
84 @retval TRUE image record is valid\r
85 @retval FALSE image record is invalid\r
86**/\r
87BOOLEAN\r
88IsImageRecordCodeSectionValid (\r
89 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
90 );\r
91\r
92/**\r
93 Get the image type.\r
94\r
95 @param[in] File This is a pointer to the device path of the file that is\r
96 being dispatched.\r
97\r
98 @return UINT32 Image Type\r
99**/\r
100UINT32\r
101GetImageType (\r
102 IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
103 )\r
104{\r
105 EFI_STATUS Status;\r
106 EFI_HANDLE DeviceHandle;\r
107 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
108\r
109 if (File == NULL) {\r
110 return IMAGE_UNKNOWN;\r
111 }\r
112\r
113 //\r
114 // First check to see if File is from a Firmware Volume\r
115 //\r
116 DeviceHandle = NULL;\r
117 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
118 Status = gBS->LocateDevicePath (\r
119 &gEfiFirmwareVolume2ProtocolGuid,\r
120 &TempDevicePath,\r
121 &DeviceHandle\r
122 );\r
123 if (!EFI_ERROR (Status)) {\r
124 Status = gBS->OpenProtocol (\r
125 DeviceHandle,\r
126 &gEfiFirmwareVolume2ProtocolGuid,\r
127 NULL,\r
128 NULL,\r
129 NULL,\r
130 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
131 );\r
132 if (!EFI_ERROR (Status)) {\r
133 return IMAGE_FROM_FV;\r
134 }\r
135 }\r
136 return IMAGE_UNKNOWN;\r
137}\r
138\r
139/**\r
140 Get UEFI image protection policy based upon image type.\r
141\r
142 @param[in] ImageType The UEFI image type\r
143\r
144 @return UEFI image protection policy\r
145**/\r
146UINT32\r
147GetProtectionPolicyFromImageType (\r
148 IN UINT32 ImageType\r
149 )\r
150{\r
151 if ((ImageType & mImageProtectionPolicy) == 0) {\r
152 return DO_NOT_PROTECT;\r
153 } else {\r
154 return PROTECT_IF_ALIGNED_ELSE_ALLOW;\r
155 }\r
156}\r
157\r
158/**\r
159 Get UEFI image protection policy based upon loaded image device path.\r
160\r
161 @param[in] LoadedImage The loaded image protocol\r
162 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
163\r
164 @return UEFI image protection policy\r
165**/\r
166UINT32\r
167GetUefiImageProtectionPolicy (\r
168 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
169 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
170 )\r
171{\r
172 BOOLEAN InSmm;\r
173 UINT32 ImageType;\r
174 UINT32 ProtectionPolicy;\r
175\r
176 //\r
177 // Check SMM\r
178 //\r
179 InSmm = FALSE;\r
180 if (gSmmBase2 != NULL) {\r
181 gSmmBase2->InSmm (gSmmBase2, &InSmm);\r
182 }\r
183 if (InSmm) {\r
184 return FALSE;\r
185 }\r
186\r
187 //\r
188 // Check DevicePath\r
189 //\r
190 if (LoadedImage == gDxeCoreLoadedImage) {\r
191 ImageType = IMAGE_FROM_FV;\r
192 } else {\r
193 ImageType = GetImageType (LoadedImageDevicePath);\r
194 }\r
195 ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);\r
196 return ProtectionPolicy;\r
197}\r
198\r
199\r
200/**\r
201 Set UEFI image memory attributes.\r
202\r
203 @param[in] BaseAddress Specified start address\r
204 @param[in] Length Specified length\r
205 @param[in] Attributes Specified attributes\r
206**/\r
207VOID\r
208SetUefiImageMemoryAttributes (\r
209 IN UINT64 BaseAddress,\r
210 IN UINT64 Length,\r
211 IN UINT64 Attributes\r
212 )\r
213{\r
214 EFI_STATUS Status;\r
215 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
216 UINT64 FinalAttributes;\r
217\r
218 Status = CoreGetMemorySpaceDescriptor(BaseAddress, &Descriptor);\r
219 ASSERT_EFI_ERROR(Status);\r
220\r
221 FinalAttributes = (Descriptor.Attributes & CACHE_ATTRIBUTE_MASK) | (Attributes & MEMORY_ATTRIBUTE_MASK);\r
222\r
223 DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));\r
224\r
225 ASSERT(gCpu != NULL);\r
226 gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);\r
227}\r
228\r
229/**\r
230 Set UEFI image protection attributes.\r
231\r
232 @param[in] ImageRecord A UEFI image record\r
233 @param[in] Protect TRUE: Protect the UEFI image.\r
234 FALSE: Unprotect the UEFI image.\r
235**/\r
236VOID\r
237SetUefiImageProtectionAttributes (\r
238 IN IMAGE_PROPERTIES_RECORD *ImageRecord,\r
239 IN BOOLEAN Protect\r
240 )\r
241{\r
242 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
243 LIST_ENTRY *ImageRecordCodeSectionLink;\r
244 LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
245 LIST_ENTRY *ImageRecordCodeSectionList;\r
246 UINT64 CurrentBase;\r
247 UINT64 ImageEnd;\r
248 UINT64 Attribute;\r
249\r
250 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
251\r
252 CurrentBase = ImageRecord->ImageBase;\r
253 ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
254\r
255 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
256 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
257 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
258 ImageRecordCodeSection = CR (\r
259 ImageRecordCodeSectionLink,\r
260 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
261 Link,\r
262 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
263 );\r
264 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
265\r
266 ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);\r
267 if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {\r
268 //\r
269 // DATA\r
270 //\r
271 if (Protect) {\r
272 Attribute = EFI_MEMORY_XP;\r
273 } else {\r
274 Attribute = 0;\r
275 }\r
276 SetUefiImageMemoryAttributes (\r
277 CurrentBase,\r
278 ImageRecordCodeSection->CodeSegmentBase - CurrentBase,\r
279 Attribute\r
280 );\r
281 }\r
282 //\r
283 // CODE\r
284 //\r
285 if (Protect) {\r
286 Attribute = EFI_MEMORY_RO;\r
287 } else {\r
288 Attribute = 0;\r
289 }\r
290 SetUefiImageMemoryAttributes (\r
291 ImageRecordCodeSection->CodeSegmentBase,\r
292 ImageRecordCodeSection->CodeSegmentSize,\r
293 Attribute\r
294 );\r
295 CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;\r
296 }\r
297 //\r
298 // Last DATA\r
299 //\r
300 ASSERT (CurrentBase <= ImageEnd);\r
301 if (CurrentBase < ImageEnd) {\r
302 //\r
303 // DATA\r
304 //\r
305 if (Protect) {\r
306 Attribute = EFI_MEMORY_XP;\r
307 } else {\r
308 Attribute = 0;\r
309 }\r
310 SetUefiImageMemoryAttributes (\r
311 CurrentBase,\r
312 ImageEnd - CurrentBase,\r
313 Attribute\r
314 );\r
315 }\r
316 return ;\r
317}\r
318\r
319/**\r
320 Return if the PE image section is aligned.\r
321\r
322 @param[in] SectionAlignment PE/COFF section alignment\r
323 @param[in] MemoryType PE/COFF image memory type\r
324\r
325 @retval TRUE The PE image section is aligned.\r
326 @retval FALSE The PE image section is not aligned.\r
327**/\r
328BOOLEAN\r
329IsMemoryProtectionSectionAligned (\r
330 IN UINT32 SectionAlignment,\r
331 IN EFI_MEMORY_TYPE MemoryType\r
332 )\r
333{\r
334 UINT32 PageAlignment;\r
335\r
336 switch (MemoryType) {\r
337 case EfiRuntimeServicesCode:\r
338 case EfiACPIMemoryNVS:\r
339 PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
340 break;\r
341 case EfiRuntimeServicesData:\r
342 case EfiACPIReclaimMemory:\r
343 ASSERT (FALSE);\r
344 PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
345 break;\r
346 case EfiBootServicesCode:\r
347 case EfiLoaderCode:\r
348 case EfiReservedMemoryType:\r
349 PageAlignment = EFI_PAGE_SIZE;\r
350 break;\r
351 default:\r
352 ASSERT (FALSE);\r
353 PageAlignment = EFI_PAGE_SIZE;\r
354 break;\r
355 }\r
356\r
357 if ((SectionAlignment & (PageAlignment - 1)) != 0) {\r
358 return FALSE;\r
359 } else {\r
360 return TRUE;\r
361 }\r
362}\r
363\r
364/**\r
365 Free Image record.\r
366\r
367 @param[in] ImageRecord A UEFI image record\r
368**/\r
369VOID\r
370FreeImageRecord (\r
371 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
372 )\r
373{\r
374 LIST_ENTRY *CodeSegmentListHead;\r
375 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
376\r
377 CodeSegmentListHead = &ImageRecord->CodeSegmentList;\r
378 while (!IsListEmpty (CodeSegmentListHead)) {\r
379 ImageRecordCodeSection = CR (\r
380 CodeSegmentListHead->ForwardLink,\r
381 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
382 Link,\r
383 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
384 );\r
385 RemoveEntryList (&ImageRecordCodeSection->Link);\r
386 FreePool (ImageRecordCodeSection);\r
387 }\r
388\r
389 if (ImageRecord->Link.ForwardLink != NULL) {\r
390 RemoveEntryList (&ImageRecord->Link);\r
391 }\r
392 FreePool (ImageRecord);\r
393}\r
394\r
395/**\r
396 Protect or unprotect UEFI image common function.\r
397\r
398 @param[in] LoadedImage The loaded image protocol\r
399 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
400 @param[in] Protect TRUE: Protect the UEFI image.\r
401 FALSE: Unprotect the UEFI image.\r
402**/\r
403VOID\r
404ProtectUefiImageCommon (\r
405 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
406 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath,\r
407 IN BOOLEAN Protect\r
408 )\r
409{\r
410 VOID *ImageAddress;\r
411 EFI_IMAGE_DOS_HEADER *DosHdr;\r
412 UINT32 PeCoffHeaderOffset;\r
413 UINT32 SectionAlignment;\r
414 EFI_IMAGE_SECTION_HEADER *Section;\r
415 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
416 UINT8 *Name;\r
417 UINTN Index;\r
418 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
419 CHAR8 *PdbPointer;\r
420 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
421 UINT16 Magic;\r
422 BOOLEAN IsAligned;\r
423 UINT32 ProtectionPolicy;\r
424\r
425 DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));\r
426 DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));\r
427\r
428 if (gCpu == NULL) {\r
429 return ;\r
430 }\r
431\r
432 ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);\r
433 switch (ProtectionPolicy) {\r
434 case DO_NOT_PROTECT:\r
435 return ;\r
436 case PROTECT_IF_ALIGNED_ELSE_ALLOW:\r
437 break;\r
438 default:\r
439 ASSERT(FALSE);\r
440 return ;\r
441 }\r
442\r
443 ImageRecord = AllocateZeroPool (sizeof(*ImageRecord));\r
444 if (ImageRecord == NULL) {\r
445 return ;\r
446 }\r
447 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;\r
448\r
449 //\r
450 // Step 1: record whole region\r
451 //\r
452 ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase;\r
453 ImageRecord->ImageSize = LoadedImage->ImageSize;\r
454\r
455 ImageAddress = LoadedImage->ImageBase;\r
456\r
457 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
458 if (PdbPointer != NULL) {\r
459 DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));\r
460 }\r
461\r
462 //\r
463 // Check PE/COFF image\r
464 //\r
465 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
466 PeCoffHeaderOffset = 0;\r
467 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
468 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
469 }\r
470\r
471 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
472 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
473 DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));\r
474 // It might be image in SMM.\r
475 goto Finish;\r
476 }\r
477\r
478 //\r
479 // Get SectionAlignment\r
480 //\r
481 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
482 //\r
483 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
484 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
485 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
486 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
487 //\r
488 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
489 } else {\r
490 //\r
491 // Get the magic value from the PE/COFF Optional Header\r
492 //\r
493 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
494 }\r
495 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
496 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
497 } else {\r
498 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
499 }\r
500\r
501 IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType);\r
502 if (!IsAligned) {\r
503 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n",\r
504 SectionAlignment));\r
505 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
506 if (PdbPointer != NULL) {\r
507 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
508 }\r
509 goto Finish;\r
510 }\r
511\r
512 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
513 (UINT8 *) (UINTN) ImageAddress +\r
514 PeCoffHeaderOffset +\r
515 sizeof(UINT32) +\r
516 sizeof(EFI_IMAGE_FILE_HEADER) +\r
517 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
518 );\r
519 ImageRecord->CodeSegmentCount = 0;\r
520 InitializeListHead (&ImageRecord->CodeSegmentList);\r
521 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
522 Name = Section[Index].Name;\r
523 DEBUG ((\r
524 DEBUG_VERBOSE,\r
525 " Section - '%c%c%c%c%c%c%c%c'\n",\r
526 Name[0],\r
527 Name[1],\r
528 Name[2],\r
529 Name[3],\r
530 Name[4],\r
531 Name[5],\r
532 Name[6],\r
533 Name[7]\r
534 ));\r
535\r
a2ed40c0
AB
536 //\r
537 // Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE\r
538 // can always be mapped read-only, classify a section as a code section only\r
539 // if it has the executable attribute set and the writable attribute cleared.\r
540 //\r
541 // This adheres more closely to the PE/COFF spec, and avoids issues with\r
542 // Linux OS loaders that may consist of a single read/write/execute section.\r
543 //\r
544 if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {\r
d0e92aad
JY
545 DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));\r
546 DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));\r
547 DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));\r
548 DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));\r
549 DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));\r
550 DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));\r
551 DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));\r
552 DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));\r
553 DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));\r
554\r
555 //\r
556 // Step 2: record code section\r
557 //\r
558 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));\r
559 if (ImageRecordCodeSection == NULL) {\r
560 return ;\r
561 }\r
562 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;\r
563\r
564 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;\r
565 ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE(Section[Index].SizeOfRawData, SectionAlignment);\r
566\r
567 DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));\r
568\r
569 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);\r
570 ImageRecord->CodeSegmentCount++;\r
571 }\r
572 }\r
573\r
574 if (ImageRecord->CodeSegmentCount == 0) {\r
575 DEBUG ((DEBUG_ERROR, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));\r
576 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
577 if (PdbPointer != NULL) {\r
578 DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
579 }\r
580 goto Finish;\r
581 }\r
582\r
583 //\r
584 // Final\r
585 //\r
586 SortImageRecordCodeSection (ImageRecord);\r
587 //\r
588 // Check overlap all section in ImageBase/Size\r
589 //\r
590 if (!IsImageRecordCodeSectionValid (ImageRecord)) {\r
591 DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));\r
592 goto Finish;\r
593 }\r
594\r
595 //\r
596 // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.\r
597 // Given that the loader always allocates full pages, we know the space after the image is not used.\r
598 //\r
599 ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);\r
600\r
601 //\r
602 // CPU ARCH present. Update memory attribute directly.\r
603 //\r
604 SetUefiImageProtectionAttributes (ImageRecord, Protect);\r
605\r
606 //\r
607 // Clean up\r
608 //\r
609 FreeImageRecord (ImageRecord);\r
610\r
611Finish:\r
612 return ;\r
613}\r
614\r
615/**\r
616 Protect UEFI image.\r
617\r
618 @param[in] LoadedImage The loaded image protocol\r
619 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
620**/\r
621VOID\r
622ProtectUefiImage (\r
623 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
624 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
625 )\r
626{\r
627 if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
628 ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, TRUE);\r
629 }\r
630}\r
631\r
632/**\r
633 Unprotect UEFI image.\r
634\r
635 @param[in] LoadedImage The loaded image protocol\r
636 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
637**/\r
638VOID\r
639UnprotectUefiImage (\r
640 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
641 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
642 )\r
643{\r
644 if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
645 ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, FALSE);\r
646 }\r
647}\r
648\r
649/**\r
650 A notification for CPU_ARCH protocol.\r
651\r
652 @param[in] Event Event whose notification function is being invoked.\r
653 @param[in] Context Pointer to the notification function's context,\r
654 which is implementation-dependent.\r
655\r
656**/\r
657VOID\r
658EFIAPI\r
659MemoryProtectionCpuArchProtocolNotify (\r
660 IN EFI_EVENT Event,\r
661 IN VOID *Context\r
662 )\r
663{\r
664 EFI_STATUS Status;\r
665 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
666 EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;\r
667 UINTN NoHandles;\r
668 EFI_HANDLE *HandleBuffer;\r
669 UINTN Index;\r
670\r
671 DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));\r
672 Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);\r
673 if (EFI_ERROR (Status)) {\r
674 return;\r
675 }\r
676\r
677 Status = gBS->LocateHandleBuffer (\r
678 ByProtocol,\r
679 &gEfiLoadedImageProtocolGuid,\r
680 NULL,\r
681 &NoHandles,\r
682 &HandleBuffer\r
683 );\r
684 if (EFI_ERROR (Status) && (NoHandles == 0)) {\r
685 return ;\r
686 }\r
687\r
688 for (Index = 0; Index < NoHandles; Index++) {\r
689 Status = gBS->HandleProtocol (\r
690 HandleBuffer[Index],\r
691 &gEfiLoadedImageProtocolGuid,\r
692 (VOID **)&LoadedImage\r
693 );\r
694 if (EFI_ERROR(Status)) {\r
695 continue;\r
696 }\r
697 Status = gBS->HandleProtocol (\r
698 HandleBuffer[Index],\r
699 &gEfiLoadedImageDevicePathProtocolGuid,\r
700 (VOID **)&LoadedImageDevicePath\r
701 );\r
702 if (EFI_ERROR(Status)) {\r
703 LoadedImageDevicePath = NULL;\r
704 }\r
705\r
706 ProtectUefiImage (LoadedImage, LoadedImageDevicePath);\r
707 }\r
708\r
709 CoreCloseEvent (Event);\r
710 return;\r
711}\r
712\r
713/**\r
714 ExitBootServices Callback function for memory protection.\r
715**/\r
716VOID\r
717MemoryProtectionExitBootServicesCallback (\r
718 VOID\r
719 )\r
720{\r
721 EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;\r
722 LIST_ENTRY *Link;\r
723\r
724 //\r
725 // We need remove the RT protection, because RT relocation need write code segment\r
726 // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.\r
727 //\r
728 // Firmware does not own page tables after ExitBootServices(), so the OS would\r
729 // have to relax protection of RT code pages across SetVirtualAddressMap(), or\r
730 // delay setting protections on RT code pages until after SetVirtualAddressMap().\r
731 // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.\r
732 //\r
733 if (mImageProtectionPolicy != 0) {\r
734 for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {\r
735 RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);\r
736 SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);\r
737 }\r
738 }\r
739}\r
740\r
741/**\r
742 Initialize Memory Protection support.\r
743**/\r
744VOID\r
745EFIAPI\r
746CoreInitializeMemoryProtection (\r
747 VOID\r
748 )\r
749{\r
750 EFI_STATUS Status;\r
751 EFI_EVENT Event;\r
752 VOID *Registration;\r
753\r
754 mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);\r
755\r
756 if (mImageProtectionPolicy != 0) {\r
757 Status = CoreCreateEvent (\r
758 EVT_NOTIFY_SIGNAL,\r
759 TPL_CALLBACK,\r
760 MemoryProtectionCpuArchProtocolNotify,\r
761 NULL,\r
762 &Event\r
763 );\r
764 ASSERT_EFI_ERROR(Status);\r
765\r
766 //\r
767 // Register for protocol notifactions on this event\r
768 //\r
769 Status = CoreRegisterProtocolNotify (\r
770 &gEfiCpuArchProtocolGuid,\r
771 Event,\r
772 &Registration\r
773 );\r
774 ASSERT_EFI_ERROR(Status);\r
775 }\r
776 return ;\r
777}\r