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