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