]> git.proxmox.com Git - mirror_edk2.git/blame - StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c
StandaloneMM: Update permissions for Standalone MM drivers memory area
[mirror_edk2.git] / StandaloneMmPkg / Library / StandaloneMmPeCoffExtraActionLib / AArch64 / StandaloneMmPeCoffExtraActionLib.c
CommitLineData
f7f94ffe
SG
1/**@file\r
2\r
3Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>\r
4Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
5Portions copyright (c) 2011 - 2018, ARM Ltd. All rights reserved.<BR>\r
6\r
7This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include <PiDxe.h>\r
18\r
19#include <Library/ArmMmuLib.h>\r
20#include <Library/BaseLib.h>\r
21#include <Library/BaseMemoryLib.h>\r
22#include <Library/DebugLib.h>\r
23#include <Library/PcdLib.h>\r
24#include <Library/PeCoffLib.h>\r
25#include <Library/PeCoffExtraActionLib.h>\r
26\r
27typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) (\r
28 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
29 IN UINT64 Length\r
30 );\r
31\r
32STATIC\r
33RETURN_STATUS\r
34UpdatePeCoffPermissions (\r
35 IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
36 IN REGION_PERMISSION_UPDATE_FUNC NoExecUpdater,\r
37 IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater\r
38 )\r
39{\r
40 RETURN_STATUS Status;\r
41 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
42 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
43 UINTN Size;\r
44 UINTN ReadSize;\r
45 UINT32 SectionHeaderOffset;\r
46 UINTN NumberOfSections;\r
47 UINTN Index;\r
48 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
49 PE_COFF_LOADER_IMAGE_CONTEXT TmpContext;\r
50 EFI_PHYSICAL_ADDRESS Base;\r
51\r
52 //\r
53 // We need to copy ImageContext since PeCoffLoaderGetImageInfo ()\r
54 // will mangle the ImageAddress field\r
55 //\r
56 CopyMem (&TmpContext, ImageContext, sizeof (TmpContext));\r
57\r
58 if (TmpContext.PeCoffHeaderOffset == 0) {\r
59 Status = PeCoffLoaderGetImageInfo (&TmpContext);\r
60 if (RETURN_ERROR (Status)) {\r
61 DEBUG ((DEBUG_ERROR,\r
62 "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n",\r
63 __FUNCTION__, Status));\r
64 return Status;\r
65 }\r
66 }\r
67\r
68 if (TmpContext.IsTeImage &&\r
69 TmpContext.ImageAddress == ImageContext->ImageAddress) {\r
70 DEBUG ((DEBUG_INFO, "%a: ignoring XIP TE image at 0x%lx\n", __FUNCTION__,\r
71 ImageContext->ImageAddress));\r
72 return RETURN_SUCCESS;\r
73 }\r
74\r
75 if (TmpContext.SectionAlignment < EFI_PAGE_SIZE) {\r
76 //\r
77 // The sections need to be at least 4 KB aligned, since that is the\r
78 // granularity at which we can tighten permissions. So just clear the\r
79 // noexec permissions on the entire region.\r
80 //\r
81 if (!TmpContext.IsTeImage) {\r
82 DEBUG ((DEBUG_WARN,\r
83 "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",\r
84 __FUNCTION__, ImageContext->ImageAddress, TmpContext.SectionAlignment));\r
85 }\r
86 Base = ImageContext->ImageAddress & ~(EFI_PAGE_SIZE - 1);\r
87 Size = ImageContext->ImageAddress - Base + ImageContext->ImageSize;\r
88 return NoExecUpdater (Base, ALIGN_VALUE (Size, EFI_PAGE_SIZE));\r
89 }\r
90\r
91 //\r
92 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much\r
93 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic\r
94 // determines if this is a PE32 or PE32+ image. The magic is in the same\r
95 // location in both images.\r
96 //\r
97 Hdr.Union = &HdrData;\r
98 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
99 ReadSize = Size;\r
100 Status = TmpContext.ImageRead (TmpContext.Handle,\r
101 TmpContext.PeCoffHeaderOffset, &Size, Hdr.Pe32);\r
102 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
103 DEBUG ((DEBUG_ERROR,\r
104 "%a: TmpContext.ImageRead () failed (Status = %r)\n",\r
105 __FUNCTION__, Status));\r
106 return Status;\r
107 }\r
108\r
109 ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);\r
110\r
111 SectionHeaderOffset = TmpContext.PeCoffHeaderOffset + sizeof (UINT32) +\r
112 sizeof (EFI_IMAGE_FILE_HEADER);\r
113 NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);\r
114\r
115 switch (Hdr.Pe32->OptionalHeader.Magic) {\r
116 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:\r
117 SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\r
118 break;\r
119 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:\r
120 SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;\r
121 break;\r
122 default:\r
123 ASSERT (FALSE);\r
124 }\r
125\r
126 //\r
127 // Iterate over the sections\r
128 //\r
129 for (Index = 0; Index < NumberOfSections; Index++) {\r
130 //\r
131 // Read section header from file\r
132 //\r
133 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
134 ReadSize = Size;\r
135 Status = TmpContext.ImageRead (TmpContext.Handle, SectionHeaderOffset,\r
136 &Size, &SectionHeader);\r
137 if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
138 DEBUG ((DEBUG_ERROR,\r
139 "%a: TmpContext.ImageRead () failed (Status = %r)\n",\r
140 __FUNCTION__, Status));\r
141 return Status;\r
142 }\r
143\r
144 Base = TmpContext.ImageAddress + SectionHeader.VirtualAddress;\r
145\r
146 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {\r
147\r
148 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0 &&\r
149 TmpContext.ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
150\r
151 DEBUG ((DEBUG_INFO,\r
152 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n",\r
153 __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));\r
154 ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize);\r
155 } else {\r
156 DEBUG ((DEBUG_WARN,\r
157 "%a: Mapping section %d of image at 0x%lx with RW-XN permissions and size 0x%x\n",\r
158 __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));\r
159 }\r
160 } else {\r
161 DEBUG ((DEBUG_INFO,\r
162 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n",\r
163 __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));\r
164 ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize);\r
165\r
166 DEBUG ((DEBUG_INFO,\r
167 "%a: Mapping section %d of image at 0x%lx with RO-X permissions and size 0x%x\n",\r
168 __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));\r
169 NoExecUpdater (Base, SectionHeader.Misc.VirtualSize);\r
170 }\r
171\r
172 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
173 }\r
174 return RETURN_SUCCESS;\r
175}\r
176\r
177/**\r
178 Performs additional actions after a PE/COFF image has been loaded and relocated.\r
179\r
180 If ImageContext is NULL, then ASSERT().\r
181\r
182 @param ImageContext Pointer to the image context structure that describes the\r
183 PE/COFF image that has already been loaded and relocated.\r
184\r
185**/\r
186VOID\r
187EFIAPI\r
188PeCoffLoaderRelocateImageExtraAction (\r
189 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
190 )\r
191{\r
192 UpdatePeCoffPermissions (\r
193 ImageContext,\r
194 ArmClearMemoryRegionNoExec,\r
195 ArmSetMemoryRegionReadOnly\r
196 );\r
197}\r
198\r
199\r
200\r
201/**\r
202 Performs additional actions just before a PE/COFF image is unloaded. Any resources\r
203 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.\r
204\r
205 If ImageContext is NULL, then ASSERT().\r
206\r
207 @param ImageContext Pointer to the image context structure that describes the\r
208 PE/COFF image that is being unloaded.\r
209\r
210**/\r
211VOID\r
212EFIAPI\r
213PeCoffLoaderUnloadImageExtraAction (\r
214 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
215 )\r
216{\r
217 UpdatePeCoffPermissions (\r
218 ImageContext,\r
219 ArmSetMemoryRegionNoExec,\r
220 ArmClearMemoryRegionReadOnly\r
221 );\r
222}\r