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