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