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>
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
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.
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>
27 typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC
) (
28 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
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
41 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
42 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
45 UINT32 SectionHeaderOffset
;
46 UINTN NumberOfSections
;
48 EFI_IMAGE_SECTION_HEADER SectionHeader
;
49 PE_COFF_LOADER_IMAGE_CONTEXT TmpContext
;
50 EFI_PHYSICAL_ADDRESS Base
;
53 // We need to copy ImageContext since PeCoffLoaderGetImageInfo ()
54 // will mangle the ImageAddress field
56 CopyMem (&TmpContext
, ImageContext
, sizeof (TmpContext
));
58 if (TmpContext
.PeCoffHeaderOffset
== 0) {
59 Status
= PeCoffLoaderGetImageInfo (&TmpContext
);
60 if (RETURN_ERROR (Status
)) {
62 "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n",
63 __FUNCTION__
, Status
));
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
;
75 if (TmpContext
.SectionAlignment
< EFI_PAGE_SIZE
) {
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.
81 if (!TmpContext
.IsTeImage
) {
83 "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
84 __FUNCTION__
, ImageContext
->ImageAddress
, TmpContext
.SectionAlignment
));
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
));
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.
98 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
100 Status
= TmpContext
.ImageRead (TmpContext
.Handle
,
101 TmpContext
.PeCoffHeaderOffset
, &Size
, Hdr
.Pe32
);
102 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
104 "%a: TmpContext.ImageRead () failed (Status = %r)\n",
105 __FUNCTION__
, Status
));
109 ASSERT (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
);
111 SectionHeaderOffset
= TmpContext
.PeCoffHeaderOffset
+ sizeof (UINT32
) +
112 sizeof (EFI_IMAGE_FILE_HEADER
);
113 NumberOfSections
= (UINTN
)(Hdr
.Pe32
->FileHeader
.NumberOfSections
);
115 switch (Hdr
.Pe32
->OptionalHeader
.Magic
) {
116 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
117 SectionHeaderOffset
+= Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
119 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
120 SectionHeaderOffset
+= Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
127 // Iterate over the sections
129 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
131 // Read section header from file
133 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
135 Status
= TmpContext
.ImageRead (TmpContext
.Handle
, SectionHeaderOffset
,
136 &Size
, &SectionHeader
);
137 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
139 "%a: TmpContext.ImageRead () failed (Status = %r)\n",
140 __FUNCTION__
, Status
));
144 Base
= TmpContext
.ImageAddress
+ SectionHeader
.VirtualAddress
;
146 if ((SectionHeader
.Characteristics
& EFI_IMAGE_SCN_MEM_EXECUTE
) == 0) {
148 if ((SectionHeader
.Characteristics
& EFI_IMAGE_SCN_MEM_WRITE
) == 0 &&
149 TmpContext
.ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
152 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n",
153 __FUNCTION__
, Index
, Base
, SectionHeader
.Misc
.VirtualSize
));
154 ReadOnlyUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
157 "%a: Mapping section %d of image at 0x%lx with RW-XN permissions and size 0x%x\n",
158 __FUNCTION__
, Index
, Base
, SectionHeader
.Misc
.VirtualSize
));
162 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n",
163 __FUNCTION__
, Index
, Base
, SectionHeader
.Misc
.VirtualSize
));
164 ReadOnlyUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
167 "%a: Mapping section %d of image at 0x%lx with RO-X permissions and size 0x%x\n",
168 __FUNCTION__
, Index
, Base
, SectionHeader
.Misc
.VirtualSize
));
169 NoExecUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
172 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
174 return RETURN_SUCCESS
;
178 Performs additional actions after a PE/COFF image has been loaded and relocated.
180 If ImageContext is NULL, then ASSERT().
182 @param ImageContext Pointer to the image context structure that describes the
183 PE/COFF image that has already been loaded and relocated.
188 PeCoffLoaderRelocateImageExtraAction (
189 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
192 UpdatePeCoffPermissions (
194 ArmClearMemoryRegionNoExec
,
195 ArmSetMemoryRegionReadOnly
202 Performs additional actions just before a PE/COFF image is unloaded. Any resources
203 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
205 If ImageContext is NULL, then ASSERT().
207 @param ImageContext Pointer to the image context structure that describes the
208 PE/COFF image that is being unloaded.
213 PeCoffLoaderUnloadImageExtraAction (
214 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
217 UpdatePeCoffPermissions (
219 ArmSetMemoryRegionNoExec
,
220 ArmClearMemoryRegionReadOnly