1 /** @file
2 Locate, get and update PE/COFF permissions during Standalone MM
3 Foundation Entry point on ARM platforms.
4
5 Copyright (c) 2017 - 2018, ARM Ltd. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10
11 #include <PiMm.h>
12
13 #include <PiPei.h>
14 #include <Guid/MmramMemoryReserve.h>
15 #include <Guid/MpInformation.h>
16
17 #include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
18 #include <Library/ArmMmuLib.h>
19 #include <Library/ArmSvcLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/HobLib.h>
22 #include <Library/BaseLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/SerialPortLib.h>
25
26 #include <IndustryStandard/ArmStdSmc.h>
27
28 EFI_STATUS
29 EFIAPI
UpdateMmFoundationPeCoffPermissions(IN CONST PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext,IN EFI_PHYSICAL_ADDRESS ImageBase,IN UINT32 SectionHeaderOffset,IN CONST UINT16 NumberOfSections,IN REGION_PERMISSION_UPDATE_FUNC TextUpdater,IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater,IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater)30 UpdateMmFoundationPeCoffPermissions (
31 IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
32 IN EFI_PHYSICAL_ADDRESS ImageBase,
33 IN UINT32 SectionHeaderOffset,
34 IN CONST UINT16 NumberOfSections,
35 IN REGION_PERMISSION_UPDATE_FUNC TextUpdater,
36 IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater,
37 IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater
38 )
39 {
40 EFI_IMAGE_SECTION_HEADER SectionHeader;
41 RETURN_STATUS Status;
42 EFI_PHYSICAL_ADDRESS Base;
43 UINTN Size;
44 UINTN ReadSize;
45 UINTN Index;
46
47 ASSERT (ImageContext != NULL);
48
49 //
50 // Iterate over the sections
51 //
52 for (Index = 0; Index < NumberOfSections; Index++) {
53 //
54 // Read section header from file
55 //
56 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
57 ReadSize = Size;
58 Status = ImageContext->ImageRead (
59 ImageContext->Handle,
60 SectionHeaderOffset,
61 &Size,
62 &SectionHeader
63 );
64
65 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
66 DEBUG ((DEBUG_ERROR,
67 "%a: ImageContext->ImageRead () failed (Status = %r)\n",
68 __FUNCTION__, Status));
69 return Status;
70 }
71
72 DEBUG ((DEBUG_INFO,
73 "%a: Section %d of image at 0x%lx has 0x%x permissions\n",
74 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
75 DEBUG ((DEBUG_INFO,
76 "%a: Section %d of image at 0x%lx has %a name\n",
77 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Name));
78 DEBUG ((DEBUG_INFO,
79 "%a: Section %d of image at 0x%lx has 0x%x address\n",
80 __FUNCTION__, Index, ImageContext->ImageAddress,
81 ImageContext->ImageAddress + SectionHeader.VirtualAddress));
82 DEBUG ((DEBUG_INFO,
83 "%a: Section %d of image at 0x%lx has 0x%x data\n",
84 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.PointerToRawData));
85
86 //
87 // If the section is marked as XN then remove the X attribute. Furthermore,
88 // if it is a writeable section then mark it appropriately as well.
89 //
90 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
91 Base = ImageBase + SectionHeader.VirtualAddress;
92
93 TextUpdater (Base, SectionHeader.Misc.VirtualSize);
94
95 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) {
96 ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize);
97 DEBUG ((DEBUG_INFO,
98 "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n",
99 __FUNCTION__, Index, ImageContext->ImageAddress));
100 } else {
101 DEBUG ((DEBUG_INFO,
102 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n",
103 __FUNCTION__, Index, ImageContext->ImageAddress));
104 }
105 } else {
106 DEBUG ((DEBUG_INFO,
107 "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n",
108 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
109 }
110 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
111 }
112
113 return RETURN_SUCCESS;
114 }
115
116 EFI_STATUS
117 EFIAPI
LocateStandaloneMmCorePeCoffData(IN EFI_FIRMWARE_VOLUME_HEADER * BfvAddress,IN OUT VOID ** TeData,IN OUT UINTN * TeDataSize)118 LocateStandaloneMmCorePeCoffData (
119 IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress,
120 IN OUT VOID **TeData,
121 IN OUT UINTN *TeDataSize
122 )
123 {
124 EFI_FFS_FILE_HEADER *FileHeader = NULL;
125 EFI_STATUS Status;
126
127 Status = FfsFindNextFile (
128 EFI_FV_FILETYPE_SECURITY_CORE,
129 BfvAddress,
130 &FileHeader
131 );
132
133 if (EFI_ERROR (Status)) {
134 DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM FFS file - 0x%x\n",
135 Status));
136 return Status;
137 }
138
139 Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, TeData, TeDataSize);
140 if (EFI_ERROR (Status)) {
141 Status = FfsFindSectionData (EFI_SECTION_TE, FileHeader, TeData, TeDataSize);
142 if (EFI_ERROR (Status)) {
143 DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Section data - %r\n",
144 Status));
145 return Status;
146 }
147 }
148
149 DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData));
150 return Status;
151 }
152
153 STATIC
154 EFI_STATUS
GetPeCoffSectionInformation(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext,OUT EFI_PHYSICAL_ADDRESS * ImageBase,OUT UINT32 * SectionHeaderOffset,OUT UINT16 * NumberOfSections)155 GetPeCoffSectionInformation (
156 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
157 OUT EFI_PHYSICAL_ADDRESS *ImageBase,
158 OUT UINT32 *SectionHeaderOffset,
159 OUT UINT16 *NumberOfSections
160 )
161 {
162 RETURN_STATUS Status;
163 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
164 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
165 UINTN Size;
166 UINTN ReadSize;
167
168 ASSERT (ImageContext != NULL);
169 ASSERT (SectionHeaderOffset != NULL);
170 ASSERT (NumberOfSections != NULL);
171
172 Status = PeCoffLoaderGetImageInfo (ImageContext);
173 if (RETURN_ERROR (Status)) {
174 DEBUG ((DEBUG_ERROR,
175 "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n",
176 __FUNCTION__, Status));
177 return Status;
178 }
179
180 if (ImageContext->SectionAlignment < EFI_PAGE_SIZE) {
181 //
182 // The sections need to be at least 4 KB aligned, since that is the
183 // granularity at which we can tighten permissions.
184 //
185 if (!ImageContext->IsTeImage) {
186 DEBUG ((DEBUG_WARN,
187 "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
188 __FUNCTION__, ImageContext->ImageAddress, ImageContext->SectionAlignment));
189 return RETURN_UNSUPPORTED;
190 }
191 ImageContext->SectionAlignment = EFI_PAGE_SIZE;
192 }
193
194 //
195 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
196 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
197 // determines if this is a PE32 or PE32+ image. The magic is in the same
198 // location in both images.
199 //
200 Hdr.Union = &HdrData;
201 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
202 ReadSize = Size;
203 Status = ImageContext->ImageRead (
204 ImageContext->Handle,
205 ImageContext->PeCoffHeaderOffset,
206 &Size,
207 Hdr.Pe32
208 );
209
210 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
211 DEBUG ((DEBUG_ERROR,
212 "%a: TmpContext->ImageRead () failed (Status = %r)\n",
213 __FUNCTION__, Status));
214 return Status;
215 }
216
217 *ImageBase = ImageContext->ImageAddress;
218 if (!ImageContext->IsTeImage) {
219 ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
220
221 *SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) +
222 sizeof (EFI_IMAGE_FILE_HEADER);
223 *NumberOfSections = Hdr.Pe32->FileHeader.NumberOfSections;
224
225 switch (Hdr.Pe32->OptionalHeader.Magic) {
226 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
227 *SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
228 break;
229 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
230 *SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
231 break;
232 default:
233 ASSERT (FALSE);
234 }
235 } else {
236 *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
237 *NumberOfSections = Hdr.Te->NumberOfSections;
238 *ImageBase -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
239 }
240 return RETURN_SUCCESS;
241 }
242
243 EFI_STATUS
244 EFIAPI
GetStandaloneMmCorePeCoffSections(IN VOID * TeData,IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext,OUT EFI_PHYSICAL_ADDRESS * ImageBase,IN OUT UINT32 * SectionHeaderOffset,IN OUT UINT16 * NumberOfSections)245 GetStandaloneMmCorePeCoffSections (
246 IN VOID *TeData,
247 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
248 OUT EFI_PHYSICAL_ADDRESS *ImageBase,
249 IN OUT UINT32 *SectionHeaderOffset,
250 IN OUT UINT16 *NumberOfSections
251 )
252 {
253 EFI_STATUS Status;
254
255 // Initialize the Image Context
256 ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
257 ImageContext->Handle = TeData;
258 ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory;
259
260 DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData));
261
262 Status = GetPeCoffSectionInformation (ImageContext, ImageBase,
263 SectionHeaderOffset, NumberOfSections);
264 if (EFI_ERROR (Status)) {
265 DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status));
266 return Status;
267 }
268
269 DEBUG ((DEBUG_INFO, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n",
270 *SectionHeaderOffset, *NumberOfSections));
271
272 return Status;
273 }
274