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