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