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 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <Library/ArmMmuLib.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/PeCoffLib.h>
19 #include <Library/PeCoffExtraActionLib.h>
21 typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC
) (
22 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
28 UpdatePeCoffPermissions (
29 IN CONST PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
30 IN REGION_PERMISSION_UPDATE_FUNC NoExecUpdater
,
31 IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater
35 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
36 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
39 UINT32 SectionHeaderOffset
;
40 UINTN NumberOfSections
;
42 EFI_IMAGE_SECTION_HEADER SectionHeader
;
43 PE_COFF_LOADER_IMAGE_CONTEXT TmpContext
;
44 EFI_PHYSICAL_ADDRESS Base
;
47 // We need to copy ImageContext since PeCoffLoaderGetImageInfo ()
48 // will mangle the ImageAddress field
50 CopyMem (&TmpContext
, ImageContext
, sizeof (TmpContext
));
52 if (TmpContext
.PeCoffHeaderOffset
== 0) {
53 Status
= PeCoffLoaderGetImageInfo (&TmpContext
);
54 if (RETURN_ERROR (Status
)) {
56 "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n",
57 __FUNCTION__
, Status
));
62 if (TmpContext
.IsTeImage
&&
63 TmpContext
.ImageAddress
== ImageContext
->ImageAddress
) {
64 DEBUG ((DEBUG_INFO
, "%a: ignoring XIP TE image at 0x%lx\n", __FUNCTION__
,
65 ImageContext
->ImageAddress
));
66 return RETURN_SUCCESS
;
69 if (TmpContext
.SectionAlignment
< EFI_PAGE_SIZE
) {
71 // The sections need to be at least 4 KB aligned, since that is the
72 // granularity at which we can tighten permissions. So just clear the
73 // noexec permissions on the entire region.
75 if (!TmpContext
.IsTeImage
) {
77 "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
78 __FUNCTION__
, ImageContext
->ImageAddress
, TmpContext
.SectionAlignment
));
80 Base
= ImageContext
->ImageAddress
& ~(EFI_PAGE_SIZE
- 1);
81 Size
= ImageContext
->ImageAddress
- Base
+ ImageContext
->ImageSize
;
82 return NoExecUpdater (Base
, ALIGN_VALUE (Size
, EFI_PAGE_SIZE
));
86 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
87 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
88 // determines if this is a PE32 or PE32+ image. The magic is in the same
89 // location in both images.
92 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
94 Status
= TmpContext
.ImageRead (TmpContext
.Handle
,
95 TmpContext
.PeCoffHeaderOffset
, &Size
, Hdr
.Pe32
);
96 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
98 "%a: TmpContext.ImageRead () failed (Status = %r)\n",
99 __FUNCTION__
, Status
));
103 ASSERT (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
);
105 SectionHeaderOffset
= TmpContext
.PeCoffHeaderOffset
+ sizeof (UINT32
) +
106 sizeof (EFI_IMAGE_FILE_HEADER
);
107 NumberOfSections
= (UINTN
)(Hdr
.Pe32
->FileHeader
.NumberOfSections
);
109 switch (Hdr
.Pe32
->OptionalHeader
.Magic
) {
110 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
111 SectionHeaderOffset
+= Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
113 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
114 SectionHeaderOffset
+= Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
121 // Iterate over the sections
123 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
125 // Read section header from file
127 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
129 Status
= TmpContext
.ImageRead (TmpContext
.Handle
, SectionHeaderOffset
,
130 &Size
, &SectionHeader
);
131 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
133 "%a: TmpContext.ImageRead () failed (Status = %r)\n",
134 __FUNCTION__
, Status
));
138 Base
= TmpContext
.ImageAddress
+ SectionHeader
.VirtualAddress
;
140 if ((SectionHeader
.Characteristics
& EFI_IMAGE_SCN_MEM_EXECUTE
) == 0) {
142 if ((SectionHeader
.Characteristics
& EFI_IMAGE_SCN_MEM_WRITE
) == 0) {
145 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n",
146 __FUNCTION__
, Index
, Base
, SectionHeader
.Misc
.VirtualSize
));
147 ReadOnlyUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
150 "%a: Mapping section %d of image at 0x%lx with RW-XN permissions and size 0x%x\n",
151 __FUNCTION__
, Index
, Base
, SectionHeader
.Misc
.VirtualSize
));
155 "%a: Mapping section %d of image at 0x%lx with RO-X permissions and size 0x%x\n",
156 __FUNCTION__
, Index
, Base
, SectionHeader
.Misc
.VirtualSize
));
157 ReadOnlyUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
158 NoExecUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
161 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
163 return RETURN_SUCCESS
;
167 Performs additional actions after a PE/COFF image has been loaded and relocated.
169 If ImageContext is NULL, then ASSERT().
171 @param ImageContext Pointer to the image context structure that describes the
172 PE/COFF image that has already been loaded and relocated.
177 PeCoffLoaderRelocateImageExtraAction (
178 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
181 UpdatePeCoffPermissions (
183 ArmClearMemoryRegionNoExec
,
184 ArmSetMemoryRegionReadOnly
191 Performs additional actions just before a PE/COFF image is unloaded. Any resources
192 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
194 If ImageContext is NULL, then ASSERT().
196 @param ImageContext Pointer to the image context structure that describes the
197 PE/COFF image that is being unloaded.
202 PeCoffLoaderUnloadImageExtraAction (
203 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
206 UpdatePeCoffPermissions (
208 ArmSetMemoryRegionNoExec
,
209 ArmClearMemoryRegionReadOnly