1 // SPDX-License-Identifier: BSD-2-Clause-Patent
3 * pe.c - helper functions for pe binaries.
4 * Copyright Peter Jones <pjones@redhat.com>
9 #include <openssl/err.h>
10 #include <openssl/bn.h>
11 #include <openssl/dh.h>
12 #include <openssl/ocsp.h>
13 #include <openssl/pkcs12.h>
14 #include <openssl/rand.h>
15 #include <openssl/crypto.h>
16 #include <openssl/ssl.h>
17 #include <openssl/x509.h>
18 #include <openssl/x509v3.h>
19 #include <openssl/rsa.h>
20 #include <openssl/dso.h>
22 #include <Library/BaseCryptLib.h>
25 * Perform basic bounds checking of the intra-image pointers
28 ImageAddress (void *image
, uint64_t size
, uint64_t address
)
30 /* ensure our local pointer isn't bigger than our size */
34 /* Insure our math won't overflow */
35 if (UINT64_MAX
- address
< (uint64_t)(intptr_t)image
)
38 /* return the absolute pointer */
39 return image
+ address
;
43 * Perform the actual relocation
46 relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT
*context
,
47 EFI_IMAGE_SECTION_HEADER
*Section
,
48 void *orig
, void *data
)
50 EFI_IMAGE_BASE_RELOCATION
*RelocBase
, *RelocBaseEnd
;
52 UINT16
*Reloc
, *RelocEnd
;
53 char *Fixup
, *FixupBase
;
57 int size
= context
->ImageSize
;
58 void *ImageEnd
= (char *)orig
+ size
;
61 /* Alright, so here's how this works:
63 * context->RelocDir gives us two things:
64 * - the VA the table of base relocation blocks are (maybe) to be
65 * mapped at (RelocDir->VirtualAddress)
66 * - the virtual size (RelocDir->Size)
68 * The .reloc section (Section here) gives us some other things:
69 * - the name! kind of. (Section->Name)
70 * - the virtual size (Section->VirtualSize), which should be the same
72 * - the virtual address (Section->VirtualAddress)
73 * - the file section size (Section->SizeOfRawData), which is
74 * a multiple of OptHdr->FileAlignment. Only useful for image
75 * validation, not really useful for iteration bounds.
76 * - the file address (Section->PointerToRawData)
77 * - a bunch of stuff we don't use that's 0 in our binaries usually
78 * - Flags (Section->Characteristics)
80 * and then the thing that's actually at the file address is an array
81 * of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind
82 * them. The SizeOfBlock field of this structure includes the
83 * structure itself, and adding it to that structure's address will
84 * yield the next entry in the array.
86 RelocBase
= ImageAddress(orig
, size
, Section
->PointerToRawData
);
87 /* RelocBaseEnd here is the address of the first entry /past/ the
89 RelocBaseEnd
= ImageAddress(orig
, size
, Section
->PointerToRawData
+
90 Section
->Misc
.VirtualSize
);
92 if (!RelocBase
&& !RelocBaseEnd
)
95 if (!RelocBase
|| !RelocBaseEnd
) {
96 perror(L
"Reloc table overflows binary\n");
97 return EFI_UNSUPPORTED
;
100 Adjust
= (UINTN
)data
- context
->ImageAddress
;
105 while (RelocBase
< RelocBaseEnd
) {
106 Reloc
= (UINT16
*) ((char *) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
108 if (RelocBase
->SizeOfBlock
== 0) {
109 perror(L
"Reloc %d block size 0 is invalid\n", n
);
110 return EFI_UNSUPPORTED
;
111 } else if (RelocBase
->SizeOfBlock
> context
->RelocDir
->Size
) {
112 perror(L
"Reloc %d block size %d greater than reloc dir"
113 "size %d, which is invalid\n", n
,
114 RelocBase
->SizeOfBlock
,
115 context
->RelocDir
->Size
);
116 return EFI_UNSUPPORTED
;
119 RelocEnd
= (UINT16
*) ((char *) RelocBase
+ RelocBase
->SizeOfBlock
);
120 if ((void *)RelocEnd
< orig
|| (void *)RelocEnd
> ImageEnd
) {
121 perror(L
"Reloc %d entry overflows binary\n", n
);
122 return EFI_UNSUPPORTED
;
125 FixupBase
= ImageAddress(data
, size
, RelocBase
->VirtualAddress
);
127 perror(L
"Reloc %d Invalid fixupbase\n", n
);
128 return EFI_UNSUPPORTED
;
131 while (Reloc
< RelocEnd
) {
132 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
133 switch ((*Reloc
) >> 12) {
134 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
137 case EFI_IMAGE_REL_BASED_HIGH
:
138 Fixup16
= (UINT16
*) Fixup
;
139 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
142 case EFI_IMAGE_REL_BASED_LOW
:
143 Fixup16
= (UINT16
*) Fixup
;
144 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
147 case EFI_IMAGE_REL_BASED_HIGHLOW
:
148 Fixup32
= (UINT32
*) Fixup
;
149 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
152 case EFI_IMAGE_REL_BASED_DIR64
:
153 Fixup64
= (UINT64
*) Fixup
;
154 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
158 perror(L
"Reloc %d Unknown relocation\n", n
);
159 return EFI_UNSUPPORTED
;
163 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
170 #define check_size_line(data, datasize_in, hashbase, hashsize, l) ({ \
171 if ((unsigned long)hashbase > \
172 (unsigned long)data + datasize_in) { \
173 efi_status = EFI_INVALID_PARAMETER; \
174 perror(L"shim.c:%d Invalid hash base 0x%016x\n", l, \
178 if ((unsigned long)hashbase + hashsize > \
179 (unsigned long)data + datasize_in) { \
180 efi_status = EFI_INVALID_PARAMETER; \
181 perror(L"shim.c:%d Invalid hash size 0x%016x\n", l, \
186 #define check_size(d, ds, h, hs) check_size_line(d, ds, h, hs, __LINE__)
189 get_section_vma (UINTN section_num
,
190 char *buffer
, size_t bufsz UNUSED
,
191 PE_COFF_LOADER_IMAGE_CONTEXT
*context
,
192 char **basep
, size_t *sizep
,
193 EFI_IMAGE_SECTION_HEADER
**sectionp
)
195 EFI_IMAGE_SECTION_HEADER
*sections
= context
->FirstSection
;
196 EFI_IMAGE_SECTION_HEADER
*section
;
197 char *base
= NULL
, *end
= NULL
;
199 if (section_num
>= context
->NumberOfSections
)
200 return EFI_NOT_FOUND
;
202 if (context
->FirstSection
== NULL
) {
203 perror(L
"Invalid section %d requested\n", section_num
);
204 return EFI_UNSUPPORTED
;
207 section
= §ions
[section_num
];
209 base
= ImageAddress (buffer
, context
->ImageSize
, section
->VirtualAddress
);
210 end
= ImageAddress (buffer
, context
->ImageSize
,
211 section
->VirtualAddress
+ section
->Misc
.VirtualSize
- 1);
213 if (!(section
->Characteristics
& EFI_IMAGE_SCN_MEM_DISCARDABLE
)) {
215 perror(L
"Section %d has invalid base address\n", section_num
);
216 return EFI_UNSUPPORTED
;
219 perror(L
"Section %d has zero size\n", section_num
);
220 return EFI_UNSUPPORTED
;
224 if (!(section
->Characteristics
& EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA
) &&
225 (section
->VirtualAddress
< context
->SizeOfHeaders
||
226 section
->PointerToRawData
< context
->SizeOfHeaders
)) {
227 perror(L
"Section %d is inside image headers\n", section_num
);
228 return EFI_UNSUPPORTED
;
232 perror(L
"Section %d has negative size\n", section_num
);
233 return EFI_UNSUPPORTED
;
243 get_section_vma_by_name (char *name
, size_t namesz
,
244 char *buffer
, size_t bufsz
,
245 PE_COFF_LOADER_IMAGE_CONTEXT
*context
,
246 char **basep
, size_t *sizep
,
247 EFI_IMAGE_SECTION_HEADER
**sectionp
)
252 if (!name
|| namesz
== 0 || !buffer
|| bufsz
< namesz
|| !context
253 || !basep
|| !sizep
|| !sectionp
)
254 return EFI_INVALID_PARAMETER
;
257 * This code currently is only used for ".reloc\0\0" and
258 * ".sbat\0\0\0", and it doesn't know how to look up longer section
262 return EFI_UNSUPPORTED
;
264 SetMem(namebuf
, sizeof(namebuf
), 0);
265 CopyMem(namebuf
, name
, MIN(namesz
, 8));
268 * Copy the executable's sections to their desired offsets
270 for (i
= 0; i
< context
->NumberOfSections
; i
++) {
272 EFI_IMAGE_SECTION_HEADER
*section
= NULL
;
276 status
= get_section_vma(i
, buffer
, bufsz
, context
, &base
, &size
, §ion
);
277 if (!EFI_ERROR(status
)) {
278 if (CompareMem(section
->Name
, namebuf
, 8) == 0) {
293 return EFI_NOT_FOUND
;
297 * Calculate the SHA1 and SHA256 hashes of a binary
301 generate_hash(char *data
, unsigned int datasize
,
302 PE_COFF_LOADER_IMAGE_CONTEXT
*context
, UINT8
*sha256hash
,
305 unsigned int sha256ctxsize
, sha1ctxsize
;
306 void *sha256ctx
= NULL
, *sha1ctx
= NULL
;
308 unsigned int hashsize
;
309 unsigned int SumOfBytesHashed
, SumOfSectionBytes
;
310 unsigned int index
, pos
;
311 EFI_IMAGE_SECTION_HEADER
*Section
;
312 EFI_IMAGE_SECTION_HEADER
*SectionHeader
= NULL
;
313 EFI_STATUS efi_status
= EFI_SUCCESS
;
314 EFI_IMAGE_DOS_HEADER
*DosHdr
= (void *)data
;
315 unsigned int PEHdr_offset
= 0;
317 if (datasize
<= sizeof (*DosHdr
) ||
318 DosHdr
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
319 perror(L
"Invalid signature\n");
320 return EFI_INVALID_PARAMETER
;
322 PEHdr_offset
= DosHdr
->e_lfanew
;
324 sha256ctxsize
= Sha256GetContextSize();
325 sha256ctx
= AllocatePool(sha256ctxsize
);
327 sha1ctxsize
= Sha1GetContextSize();
328 sha1ctx
= AllocatePool(sha1ctxsize
);
330 if (!sha256ctx
|| !sha1ctx
) {
331 perror(L
"Unable to allocate memory for hash context\n");
332 return EFI_OUT_OF_RESOURCES
;
335 if (!Sha256Init(sha256ctx
) || !Sha1Init(sha1ctx
)) {
336 perror(L
"Unable to initialise hash\n");
337 efi_status
= EFI_OUT_OF_RESOURCES
;
341 /* Hash start to checksum */
343 hashsize
= (char *)&context
->PEHdr
->Pe32
.OptionalHeader
.CheckSum
-
345 check_size(data
, datasize
, hashbase
, hashsize
);
347 if (!(Sha256Update(sha256ctx
, hashbase
, hashsize
)) ||
348 !(Sha1Update(sha1ctx
, hashbase
, hashsize
))) {
349 perror(L
"Unable to generate hash\n");
350 efi_status
= EFI_OUT_OF_RESOURCES
;
354 /* Hash post-checksum to start of certificate table */
355 hashbase
= (char *)&context
->PEHdr
->Pe32
.OptionalHeader
.CheckSum
+
357 hashsize
= (char *)context
->SecDir
- hashbase
;
358 check_size(data
, datasize
, hashbase
, hashsize
);
360 if (!(Sha256Update(sha256ctx
, hashbase
, hashsize
)) ||
361 !(Sha1Update(sha1ctx
, hashbase
, hashsize
))) {
362 perror(L
"Unable to generate hash\n");
363 efi_status
= EFI_OUT_OF_RESOURCES
;
367 /* Hash end of certificate table to end of image header */
368 EFI_IMAGE_DATA_DIRECTORY
*dd
= context
->SecDir
+ 1;
369 hashbase
= (char *)dd
;
370 hashsize
= context
->SizeOfHeaders
- (unsigned long)((char *)dd
- data
);
371 if (hashsize
> datasize
) {
372 perror(L
"Data Directory size %d is invalid\n", hashsize
);
373 efi_status
= EFI_INVALID_PARAMETER
;
376 check_size(data
, datasize
, hashbase
, hashsize
);
378 if (!(Sha256Update(sha256ctx
, hashbase
, hashsize
)) ||
379 !(Sha1Update(sha1ctx
, hashbase
, hashsize
))) {
380 perror(L
"Unable to generate hash\n");
381 efi_status
= EFI_OUT_OF_RESOURCES
;
386 SumOfBytesHashed
= context
->SizeOfHeaders
;
389 * XXX Do we need this here, or is it already done in all cases?
391 if (context
->NumberOfSections
== 0 ||
392 context
->FirstSection
== NULL
) {
396 EFI_IMAGE_SECTION_HEADER
*section0
, *sectionN
;
398 nsections
= context
->PEHdr
->Pe32
.FileHeader
.NumberOfSections
;
399 opthdrsz
= context
->PEHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
;
401 /* Validate section0 is within image */
402 addr
= PEHdr_offset
+ sizeof(UINT32
)
403 + sizeof(EFI_IMAGE_FILE_HEADER
)
405 section0
= ImageAddress(data
, datasize
, addr
);
407 perror(L
"Malformed file header.\n");
408 perror(L
"Image address for Section Header 0 is 0x%016llx\n",
410 perror(L
"File size is 0x%016llx\n", datasize
);
411 efi_status
= EFI_INVALID_PARAMETER
;
415 /* Validate sectionN is within image */
416 addr
+= (uint64_t)(intptr_t)§ion0
[nsections
-1] -
417 (uint64_t)(intptr_t)section0
;
418 sectionN
= ImageAddress(data
, datasize
, addr
);
420 perror(L
"Malformed file header.\n");
421 perror(L
"Image address for Section Header %d is 0x%016llx\n",
422 nsections
- 1, addr
);
423 perror(L
"File size is 0x%016llx\n", datasize
);
424 efi_status
= EFI_INVALID_PARAMETER
;
428 context
->NumberOfSections
= nsections
;
429 context
->FirstSection
= section0
;
433 * Allocate a new section table so we can sort them without
434 * modifying the image.
436 SectionHeader
= AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER
)
437 * context
->NumberOfSections
);
438 if (SectionHeader
== NULL
) {
439 perror(L
"Unable to allocate section header\n");
440 efi_status
= EFI_OUT_OF_RESOURCES
;
445 * Validate section locations and sizes, and sort the table into
446 * our newly allocated header table
448 SumOfSectionBytes
= 0;
449 Section
= context
->FirstSection
;
450 for (index
= 0; index
< context
->NumberOfSections
; index
++) {
451 EFI_IMAGE_SECTION_HEADER
*SectionPtr
;
455 efi_status
= get_section_vma(index
, data
, datasize
, context
,
456 &base
, &size
, &SectionPtr
);
457 if (efi_status
== EFI_NOT_FOUND
)
459 if (EFI_ERROR(efi_status
)) {
460 perror(L
"Malformed section header\n");
464 /* Validate section size is within image. */
465 if (SectionPtr
->SizeOfRawData
>
466 datasize
- SumOfBytesHashed
- SumOfSectionBytes
) {
467 perror(L
"Malformed section %d size\n", index
);
468 efi_status
= EFI_INVALID_PARAMETER
;
471 SumOfSectionBytes
+= SectionPtr
->SizeOfRawData
;
474 while ((pos
> 0) && (Section
->PointerToRawData
< SectionHeader
[pos
- 1].PointerToRawData
)) {
475 CopyMem (&SectionHeader
[pos
], &SectionHeader
[pos
- 1], sizeof (EFI_IMAGE_SECTION_HEADER
));
478 CopyMem (&SectionHeader
[pos
], Section
, sizeof (EFI_IMAGE_SECTION_HEADER
));
483 /* Hash the sections */
484 for (index
= 0; index
< context
->NumberOfSections
; index
++) {
485 Section
= &SectionHeader
[index
];
486 if (Section
->SizeOfRawData
== 0) {
490 hashbase
= ImageAddress(data
, datasize
,
491 Section
->PointerToRawData
);
493 perror(L
"Malformed section header\n");
494 efi_status
= EFI_INVALID_PARAMETER
;
498 /* Verify hashsize within image. */
499 if (Section
->SizeOfRawData
>
500 datasize
- Section
->PointerToRawData
) {
501 perror(L
"Malformed section raw size %d\n", index
);
502 efi_status
= EFI_INVALID_PARAMETER
;
505 hashsize
= (unsigned int) Section
->SizeOfRawData
;
506 check_size(data
, datasize
, hashbase
, hashsize
);
508 if (!(Sha256Update(sha256ctx
, hashbase
, hashsize
)) ||
509 !(Sha1Update(sha1ctx
, hashbase
, hashsize
))) {
510 perror(L
"Unable to generate hash\n");
511 efi_status
= EFI_OUT_OF_RESOURCES
;
514 SumOfBytesHashed
+= Section
->SizeOfRawData
;
517 /* Hash all remaining data up to SecDir if SecDir->Size is not 0 */
518 if (datasize
> SumOfBytesHashed
&& context
->SecDir
->Size
) {
519 hashbase
= data
+ SumOfBytesHashed
;
520 hashsize
= datasize
- context
->SecDir
->Size
- SumOfBytesHashed
;
522 if ((datasize
- SumOfBytesHashed
< context
->SecDir
->Size
) ||
523 (SumOfBytesHashed
+ hashsize
!= context
->SecDir
->VirtualAddress
)) {
524 perror(L
"Malformed binary after Attribute Certificate Table\n");
525 console_print(L
"datasize: %u SumOfBytesHashed: %u SecDir->Size: %lu\n",
526 datasize
, SumOfBytesHashed
, context
->SecDir
->Size
);
527 console_print(L
"hashsize: %u SecDir->VirtualAddress: 0x%08lx\n",
528 hashsize
, context
->SecDir
->VirtualAddress
);
529 efi_status
= EFI_INVALID_PARAMETER
;
532 check_size(data
, datasize
, hashbase
, hashsize
);
534 if (!(Sha256Update(sha256ctx
, hashbase
, hashsize
)) ||
535 !(Sha1Update(sha1ctx
, hashbase
, hashsize
))) {
536 perror(L
"Unable to generate hash\n");
537 efi_status
= EFI_OUT_OF_RESOURCES
;
543 #else // we have to migrate to doing this later :/
544 SumOfBytesHashed
+= hashsize
;
547 /* Hash all remaining data */
548 if (datasize
> SumOfBytesHashed
) {
549 hashbase
= data
+ SumOfBytesHashed
;
550 hashsize
= datasize
- SumOfBytesHashed
;
552 check_size(data
, datasize
, hashbase
, hashsize
);
554 if (!(Sha256Update(sha256ctx
, hashbase
, hashsize
)) ||
555 !(Sha1Update(sha1ctx
, hashbase
, hashsize
))) {
556 perror(L
"Unable to generate hash\n");
557 efi_status
= EFI_OUT_OF_RESOURCES
;
561 SumOfBytesHashed
+= hashsize
;
565 if (!(Sha256Final(sha256ctx
, sha256hash
)) ||
566 !(Sha1Final(sha1ctx
, sha1hash
))) {
567 perror(L
"Unable to finalise hash\n");
568 efi_status
= EFI_OUT_OF_RESOURCES
;
572 dprint(L
"sha1 authenticode hash:\n");
573 dhexdumpat(sha1hash
, SHA1_DIGEST_SIZE
, 0);
574 dprint(L
"sha256 authenticode hash:\n");
575 dhexdumpat(sha256hash
, SHA256_DIGEST_SIZE
, 0);
579 FreePool(SectionHeader
);
589 * i686 x86_64 aarch64
590 * 64-on-64: nyet yes yes
591 * 64-on-32: nyet yes nyet
592 * 32-on-32: yes yes no
597 #if defined(__x86_64__) || defined(__aarch64__)
599 #elif defined(__i386__) || defined(__i686__)
600 /* Right now blindly assuming the kernel will correctly detect this
601 * and /halt the system/ if you're not really on a 64-bit cpu */
605 #else /* assuming everything else is 32-bit... */
613 #if defined(__x86_64__)
614 #if defined(ALLOW_32BIT_KERNEL_ON_X64)
621 #elif defined(__i386__) || defined(__i686__)
623 #elif defined(__aarch64__)
625 #else /* assuming everything else is 32-bit... */
631 image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION
*PEHdr
)
633 /* .Magic is the same offset in all cases */
634 if (PEHdr
->Pe32Plus
.OptionalHeader
.Magic
635 == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
640 static const UINT16 machine_type
=
641 #if defined(__x86_64__)
642 IMAGE_FILE_MACHINE_X64
;
643 #elif defined(__aarch64__)
644 IMAGE_FILE_MACHINE_ARM64
;
645 #elif defined(__arm__)
646 IMAGE_FILE_MACHINE_ARMTHUMB_MIXED
;
647 #elif defined(__i386__) || defined(__i486__) || defined(__i686__)
648 IMAGE_FILE_MACHINE_I386
;
649 #elif defined(__ia64__)
650 IMAGE_FILE_MACHINE_IA64
;
652 #error this architecture is not supported by shim
656 image_is_loadable(EFI_IMAGE_OPTIONAL_HEADER_UNION
*PEHdr
)
658 /* If the machine type doesn't match the binary, bail, unless
659 * we're in an allowed 64-on-32 scenario */
660 if (PEHdr
->Pe32
.FileHeader
.Machine
!= machine_type
) {
661 if (!(machine_type
== IMAGE_FILE_MACHINE_I386
&&
662 PEHdr
->Pe32
.FileHeader
.Machine
== IMAGE_FILE_MACHINE_X64
&&
668 /* If it's not a header type we recognize at all, bail */
669 switch (PEHdr
->Pe32Plus
.OptionalHeader
.Magic
) {
670 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
671 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
677 /* and now just check for general 64-vs-32 compatibility */
678 if (image_is_64_bit(PEHdr
)) {
689 * Read the binary header and grab appropriate information from it
692 read_header(void *data
, unsigned int datasize
,
693 PE_COFF_LOADER_IMAGE_CONTEXT
*context
)
695 EFI_IMAGE_DOS_HEADER
*DosHdr
= data
;
696 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PEHdr
= data
;
697 unsigned long HeaderWithoutDataDir
, SectionHeaderOffset
, OptHeaderSize
;
698 unsigned long FileAlignment
= 0;
701 if (datasize
< sizeof (PEHdr
->Pe32
)) {
702 perror(L
"Invalid image\n");
703 return EFI_UNSUPPORTED
;
706 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
)
707 PEHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((char *)data
+ DosHdr
->e_lfanew
);
709 if (!image_is_loadable(PEHdr
)) {
710 perror(L
"Platform does not support this image\n");
711 return EFI_UNSUPPORTED
;
714 if (image_is_64_bit(PEHdr
)) {
715 context
->NumberOfRvaAndSizes
= PEHdr
->Pe32Plus
.OptionalHeader
.NumberOfRvaAndSizes
;
716 context
->SizeOfHeaders
= PEHdr
->Pe32Plus
.OptionalHeader
.SizeOfHeaders
;
717 context
->ImageSize
= PEHdr
->Pe32Plus
.OptionalHeader
.SizeOfImage
;
718 context
->SectionAlignment
= PEHdr
->Pe32Plus
.OptionalHeader
.SectionAlignment
;
719 FileAlignment
= PEHdr
->Pe32Plus
.OptionalHeader
.FileAlignment
;
720 OptHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER64
);
722 context
->NumberOfRvaAndSizes
= PEHdr
->Pe32
.OptionalHeader
.NumberOfRvaAndSizes
;
723 context
->SizeOfHeaders
= PEHdr
->Pe32
.OptionalHeader
.SizeOfHeaders
;
724 context
->ImageSize
= (UINT64
)PEHdr
->Pe32
.OptionalHeader
.SizeOfImage
;
725 context
->SectionAlignment
= PEHdr
->Pe32
.OptionalHeader
.SectionAlignment
;
726 FileAlignment
= PEHdr
->Pe32
.OptionalHeader
.FileAlignment
;
727 OptHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER32
);
730 if (FileAlignment
% 2 != 0) {
731 perror(L
"File Alignment is invalid (%d)\n", FileAlignment
);
732 return EFI_UNSUPPORTED
;
734 if (FileAlignment
== 0)
735 FileAlignment
= 0x200;
736 if (context
->SectionAlignment
== 0)
737 context
->SectionAlignment
= PAGE_SIZE
;
738 if (context
->SectionAlignment
< FileAlignment
)
739 context
->SectionAlignment
= FileAlignment
;
741 context
->NumberOfSections
= PEHdr
->Pe32
.FileHeader
.NumberOfSections
;
743 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< context
->NumberOfRvaAndSizes
) {
744 perror(L
"Image header too small\n");
745 return EFI_UNSUPPORTED
;
748 HeaderWithoutDataDir
= OptHeaderSize
749 - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
750 if (((UINT32
)PEHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
751 context
->NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
752 perror(L
"Image header overflows data directory\n");
753 return EFI_UNSUPPORTED
;
756 SectionHeaderOffset
= DosHdr
->e_lfanew
758 + sizeof (EFI_IMAGE_FILE_HEADER
)
759 + PEHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
;
760 if (((UINT32
)context
->ImageSize
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
761 <= context
->NumberOfSections
) {
762 perror(L
"Image sections overflow image size\n");
763 return EFI_UNSUPPORTED
;
766 if ((context
->SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
767 < (UINT32
)context
->NumberOfSections
) {
768 perror(L
"Image sections overflow section headers\n");
769 return EFI_UNSUPPORTED
;
772 if ((((UINT8
*)PEHdr
- (UINT8
*)data
) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION
)) > datasize
) {
773 perror(L
"Invalid image\n");
774 return EFI_UNSUPPORTED
;
777 if (PEHdr
->Te
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
778 perror(L
"Unsupported image type\n");
779 return EFI_UNSUPPORTED
;
782 if (PEHdr
->Pe32
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) {
783 perror(L
"Unsupported image - Relocations have been stripped\n");
784 return EFI_UNSUPPORTED
;
787 context
->PEHdr
= PEHdr
;
789 if (image_is_64_bit(PEHdr
)) {
790 context
->ImageAddress
= PEHdr
->Pe32Plus
.OptionalHeader
.ImageBase
;
791 context
->EntryPoint
= PEHdr
->Pe32Plus
.OptionalHeader
.AddressOfEntryPoint
;
792 context
->RelocDir
= &PEHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
793 context
->SecDir
= &PEHdr
->Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
];
794 DllFlags
= PEHdr
->Pe32Plus
.OptionalHeader
.DllCharacteristics
;
796 context
->ImageAddress
= PEHdr
->Pe32
.OptionalHeader
.ImageBase
;
797 context
->EntryPoint
= PEHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
798 context
->RelocDir
= &PEHdr
->Pe32
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
799 context
->SecDir
= &PEHdr
->Pe32
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
];
800 DllFlags
= PEHdr
->Pe32
.OptionalHeader
.DllCharacteristics
;
803 if ((mok_policy
& MOK_POLICY_REQUIRE_NX
) &&
804 !(DllFlags
& EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT
)) {
805 perror(L
"Policy requires NX, but image does not support NX\n");
806 return EFI_UNSUPPORTED
;
809 context
->FirstSection
= (EFI_IMAGE_SECTION_HEADER
*)((char *)PEHdr
+ PEHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
+ sizeof(UINT32
) + sizeof(EFI_IMAGE_FILE_HEADER
));
811 if (context
->ImageSize
< context
->SizeOfHeaders
) {
812 perror(L
"Invalid image\n");
813 return EFI_UNSUPPORTED
;
816 if ((unsigned long)((UINT8
*)context
->SecDir
- (UINT8
*)data
) >
817 (datasize
- sizeof(EFI_IMAGE_DATA_DIRECTORY
))) {
818 perror(L
"Invalid image\n");
819 return EFI_UNSUPPORTED
;
822 if (context
->SecDir
->VirtualAddress
> datasize
||
823 (context
->SecDir
->VirtualAddress
== datasize
&&
824 context
->SecDir
->Size
> 0)) {
825 perror(L
"Malformed security header\n");
826 return EFI_INVALID_PARAMETER
;
832 verify_sbat_section(char *SBATBase
, size_t SBATSize
)
835 EFI_STATUS efi_status
;
837 struct sbat_section_entry
**entries
= NULL
;
841 if (list_empty(&sbat_var
))
844 if (SBATBase
== NULL
|| SBATSize
== 0) {
845 dprint(L
"No .sbat section data\n");
847 * SBAT is mandatory for binaries loaded by shim, but optional
848 * for binaries loaded outside of shim but verified via the
851 return in_protocol
? EFI_SUCCESS
: EFI_SECURITY_VIOLATION
;
854 sbat_size
= SBATSize
+ 1;
855 sbat_data
= AllocatePool(sbat_size
);
857 console_print(L
"Failed to allocate .sbat section buffer\n");
858 return EFI_OUT_OF_RESOURCES
;
860 CopyMem(sbat_data
, SBATBase
, SBATSize
);
861 sbat_data
[SBATSize
] = '\0';
863 efi_status
= parse_sbat_section(sbat_data
, sbat_size
, &n
, &entries
);
864 if (EFI_ERROR(efi_status
)) {
865 perror(L
"Could not parse .sbat section data: %r\n", efi_status
);
869 dprint(L
"SBAT section data\n");
870 for (i
= 0; i
< n
; i
++) {
871 dprint(L
"%a, %a, %a, %a, %a, %a\n",
872 entries
[i
]->component_name
,
873 entries
[i
]->component_generation
,
874 entries
[i
]->vendor_name
,
875 entries
[i
]->vendor_package_name
,
876 entries
[i
]->vendor_version
,
877 entries
[i
]->vendor_url
);
880 efi_status
= verify_sbat(n
, entries
);
882 cleanup_sbat_section_entries(n
, entries
);
890 static inline uint64_t
891 shim_mem_attrs_to_uefi_mem_attrs (uint64_t attrs
)
893 uint64_t ret
= EFI_MEMORY_RP
|
897 if (attrs
& MEM_ATTR_R
)
898 ret
&= ~EFI_MEMORY_RP
;
900 if (attrs
& MEM_ATTR_W
)
901 ret
&= ~EFI_MEMORY_RO
;
903 if (attrs
& MEM_ATTR_X
)
904 ret
&= ~EFI_MEMORY_XP
;
909 static inline uint64_t
910 uefi_mem_attrs_to_shim_mem_attrs (uint64_t attrs
)
912 uint64_t ret
= MEM_ATTR_R
|
916 if (attrs
& EFI_MEMORY_RP
)
919 if (attrs
& EFI_MEMORY_RO
)
922 if (attrs
& EFI_MEMORY_XP
)
929 get_mem_attrs (uintptr_t addr
, size_t size
, uint64_t *attrs
)
931 EFI_MEMORY_ATTRIBUTE_PROTOCOL
*proto
= NULL
;
932 EFI_PHYSICAL_ADDRESS physaddr
= addr
;
933 EFI_STATUS efi_status
;
935 efi_status
= LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID
,
937 if (EFI_ERROR(efi_status
) || !proto
)
940 if (physaddr
& 0xfff || size
& 0xfff || size
== 0 || attrs
== NULL
) {
941 dprint(L
"%a called on 0x%llx-0x%llx and attrs 0x%llx\n",
942 __func__
, (unsigned long long)physaddr
,
943 (unsigned long long)(physaddr
+size
-1),
948 efi_status
= proto
->GetMemoryAttributes(proto
, physaddr
, size
, attrs
);
949 *attrs
= uefi_mem_attrs_to_shim_mem_attrs (*attrs
);
955 update_mem_attrs(uintptr_t addr
, uint64_t size
,
956 uint64_t set_attrs
, uint64_t clear_attrs
)
958 EFI_MEMORY_ATTRIBUTE_PROTOCOL
*proto
= NULL
;
959 EFI_PHYSICAL_ADDRESS physaddr
= addr
;
960 EFI_STATUS efi_status
, ret
;
961 uint64_t before
= 0, after
= 0, uefi_set_attrs
, uefi_clear_attrs
;
963 efi_status
= LibLocateProtocol(&EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID
,
965 if (EFI_ERROR(efi_status
) || !proto
)
968 efi_status
= get_mem_attrs (addr
, size
, &before
);
969 if (EFI_ERROR(efi_status
))
970 dprint(L
"get_mem_attrs(0x%llx, 0x%llx, 0x%llx) -> 0x%lx\n",
971 (unsigned long long)addr
, (unsigned long long)size
,
972 &before
, efi_status
);
974 if (physaddr
& 0xfff || size
& 0xfff || size
== 0) {
975 dprint(L
"%a called on 0x%llx-0x%llx (size 0x%llx) +%a%a%a -%a%a%a\n",
976 __func__
, (unsigned long long)physaddr
,
977 (unsigned long long)(physaddr
+ size
- 1),
978 (unsigned long long)size
,
979 (set_attrs
& MEM_ATTR_R
) ? "r" : "",
980 (set_attrs
& MEM_ATTR_W
) ? "w" : "",
981 (set_attrs
& MEM_ATTR_X
) ? "x" : "",
982 (clear_attrs
& MEM_ATTR_R
) ? "r" : "",
983 (clear_attrs
& MEM_ATTR_W
) ? "w" : "",
984 (clear_attrs
& MEM_ATTR_X
) ? "x" : "");
988 uefi_set_attrs
= shim_mem_attrs_to_uefi_mem_attrs (set_attrs
);
989 dprint("translating set_attrs from 0x%lx to 0x%lx\n", set_attrs
, uefi_set_attrs
);
990 uefi_clear_attrs
= shim_mem_attrs_to_uefi_mem_attrs (clear_attrs
);
991 dprint("translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs
, uefi_clear_attrs
);
992 efi_status
= EFI_SUCCESS
;
994 efi_status
= proto
->SetMemoryAttributes(proto
, physaddr
, size
, uefi_set_attrs
);
995 if (!EFI_ERROR(efi_status
) && uefi_clear_attrs
)
996 efi_status
= proto
->ClearMemoryAttributes(proto
, physaddr
, size
, uefi_clear_attrs
);
999 efi_status
= get_mem_attrs (addr
, size
, &after
);
1000 if (EFI_ERROR(efi_status
))
1001 dprint(L
"get_mem_attrs(0x%llx, %llu, 0x%llx) -> 0x%lx\n",
1002 (unsigned long long)addr
, (unsigned long long)size
,
1003 &after
, efi_status
);
1005 dprint(L
"set +%a%a%a -%a%a%a on 0x%llx-0x%llx before:%c%c%c after:%c%c%c\n",
1006 (set_attrs
& MEM_ATTR_R
) ? "r" : "",
1007 (set_attrs
& MEM_ATTR_W
) ? "w" : "",
1008 (set_attrs
& MEM_ATTR_X
) ? "x" : "",
1009 (clear_attrs
& MEM_ATTR_R
) ? "r" : "",
1010 (clear_attrs
& MEM_ATTR_W
) ? "w" : "",
1011 (clear_attrs
& MEM_ATTR_X
) ? "x" : "",
1012 (unsigned long long)addr
, (unsigned long long)(addr
+ size
- 1),
1013 (before
& MEM_ATTR_R
) ? 'r' : '-',
1014 (before
& MEM_ATTR_W
) ? 'w' : '-',
1015 (before
& MEM_ATTR_X
) ? 'x' : '-',
1016 (after
& MEM_ATTR_R
) ? 'r' : '-',
1017 (after
& MEM_ATTR_W
) ? 'w' : '-',
1018 (after
& MEM_ATTR_X
) ? 'x' : '-');
1023 EFI_STATUS
verify_image(void *data
, unsigned int datasize
,
1024 EFI_LOADED_IMAGE
*li
,
1025 PE_COFF_LOADER_IMAGE_CONTEXT
*context
)
1027 EFI_STATUS efi_status
;
1028 UINT8 sha1hash
[SHA1_DIGEST_SIZE
];
1029 UINT8 sha256hash
[SHA256_DIGEST_SIZE
];
1032 * The binary header contains relevant context and section pointers
1034 efi_status
= read_header(data
, datasize
, context
);
1035 if (EFI_ERROR(efi_status
)) {
1036 perror(L
"Failed to read header: %r\n", efi_status
);
1041 * Perform the image verification before we start copying data around
1042 * in order to load it.
1044 if (secure_mode()) {
1045 efi_status
= verify_buffer(data
, datasize
,
1046 context
, sha256hash
, sha1hash
);
1047 if (EFI_ERROR(efi_status
)) {
1049 console_print(L
"Verification failed: %r\n", efi_status
);
1051 console_error(L
"Verification failed", efi_status
);
1054 console_print(L
"Verification succeeded\n");
1058 * Calculate the hash for the TPM measurement.
1059 * XXX: We're computing these twice in secure boot mode when the
1060 * buffers already contain the previously computed hashes. Also,
1061 * this is only useful for the TPM1.2 case. We should try to fix
1062 * this in a follow-up.
1064 efi_status
= generate_hash(data
, datasize
, context
, sha256hash
,
1066 if (EFI_ERROR(efi_status
))
1069 /* Measure the binary into the TPM */
1073 tpm_log_pe((EFI_PHYSICAL_ADDRESS
)(UINTN
)data
, datasize
,
1074 (EFI_PHYSICAL_ADDRESS
)(UINTN
)context
->ImageAddress
,
1075 li
->FilePath
, sha1hash
, 4);
1077 if (efi_status
!= EFI_SUCCESS
) {
1086 * Once the image has been loaded it needs to be validated and relocated
1089 handle_image (void *data
, unsigned int datasize
,
1090 EFI_LOADED_IMAGE
*li
,
1091 EFI_IMAGE_ENTRY_POINT
*entry_point
,
1092 EFI_PHYSICAL_ADDRESS
*alloc_address
,
1095 EFI_STATUS efi_status
;
1098 EFI_IMAGE_SECTION_HEADER
*Section
;
1101 PE_COFF_LOADER_IMAGE_CONTEXT context
;
1102 unsigned int alignment
, alloc_size
;
1103 int found_entry_point
= 0;
1104 UINT8 sha1hash
[SHA1_DIGEST_SIZE
];
1105 UINT8 sha256hash
[SHA256_DIGEST_SIZE
];
1108 * The binary header contains relevant context and section pointers
1110 efi_status
= read_header(data
, datasize
, &context
);
1111 if (EFI_ERROR(efi_status
)) {
1112 perror(L
"Failed to read header: %r\n", efi_status
);
1117 * Perform the image verification before we start copying data around
1118 * in order to load it.
1120 if (secure_mode ()) {
1121 efi_status
= verify_buffer(data
, datasize
, &context
, sha256hash
,
1124 if (EFI_ERROR(efi_status
)) {
1126 console_print(L
"Verification failed: %r\n", efi_status
);
1128 console_error(L
"Verification failed", efi_status
);
1132 console_print(L
"Verification succeeded\n");
1137 * Calculate the hash for the TPM measurement.
1138 * XXX: We're computing these twice in secure boot mode when the
1139 * buffers already contain the previously computed hashes. Also,
1140 * this is only useful for the TPM1.2 case. We should try to fix
1141 * this in a follow-up.
1143 efi_status
= generate_hash(data
, datasize
, &context
, sha256hash
,
1145 if (EFI_ERROR(efi_status
))
1148 /* Measure the binary into the TPM */
1152 tpm_log_pe((EFI_PHYSICAL_ADDRESS
)(UINTN
)data
, datasize
,
1153 (EFI_PHYSICAL_ADDRESS
)(UINTN
)context
.ImageAddress
,
1154 li
->FilePath
, sha1hash
, 4);
1156 if (efi_status
!= EFI_SUCCESS
) {
1161 /* The spec says, uselessly, of SectionAlignment:
1163 * The alignment (in bytes) of sections when they are loaded into
1164 * memory. It must be greater than or equal to FileAlignment. The
1165 * default is the page size for the architecture.
1167 * Which doesn't tell you whose responsibility it is to enforce the
1168 * "default", or when. It implies that the value in the field must
1169 * be > FileAlignment (also poorly defined), but it appears visual
1170 * studio will happily write 512 for FileAlignment (its default) and
1171 * 0 for SectionAlignment, intending to imply PAGE_SIZE.
1173 * We only support one page size, so if it's zero, nerf it to 4096.
1175 alignment
= context
.SectionAlignment
;
1179 alloc_size
= ALIGN_VALUE(context
.ImageSize
+ context
.SectionAlignment
,
1181 *alloc_pages
= alloc_size
/ PAGE_SIZE
;
1183 efi_status
= BS
->AllocatePages(AllocateAnyPages
, EfiLoaderCode
,
1184 *alloc_pages
, alloc_address
);
1185 if (EFI_ERROR(efi_status
)) {
1186 perror(L
"Failed to allocate image buffer\n");
1187 return EFI_OUT_OF_RESOURCES
;
1190 buffer
= (void *)ALIGN_VALUE((unsigned long)*alloc_address
, alignment
);
1191 dprint(L
"Loading 0x%llx bytes at 0x%llx\n",
1192 (unsigned long long)context
.ImageSize
,
1193 (unsigned long long)(uintptr_t)buffer
);
1194 update_mem_attrs((uintptr_t)buffer
, alloc_size
, MEM_ATTR_R
|MEM_ATTR_W
,
1197 CopyMem(buffer
, data
, context
.SizeOfHeaders
);
1199 *entry_point
= ImageAddress(buffer
, context
.ImageSize
, context
.EntryPoint
);
1200 if (!*entry_point
) {
1201 perror(L
"Entry point is invalid\n");
1202 BS
->FreePages(*alloc_address
, *alloc_pages
);
1203 return EFI_UNSUPPORTED
;
1206 char *RelocBase
, *RelocBaseEnd
;
1208 * These are relative virtual addresses, so we have to check them
1209 * against the image size, not the data size.
1211 RelocBase
= ImageAddress(buffer
, context
.ImageSize
,
1212 context
.RelocDir
->VirtualAddress
);
1214 * RelocBaseEnd here is the address of the last byte of the table
1216 RelocBaseEnd
= ImageAddress(buffer
, context
.ImageSize
,
1217 context
.RelocDir
->VirtualAddress
+
1218 context
.RelocDir
->Size
- 1);
1220 EFI_IMAGE_SECTION_HEADER
*RelocSection
= NULL
;
1223 * Copy the executable's sections to their desired offsets
1225 Section
= context
.FirstSection
;
1226 for (i
= 0; i
< context
.NumberOfSections
; i
++, Section
++) {
1227 /* Don't try to copy discardable sections with zero size */
1228 if ((Section
->Characteristics
& EFI_IMAGE_SCN_MEM_DISCARDABLE
) &&
1229 !Section
->Misc
.VirtualSize
)
1233 * Skip sections that aren't marked readable.
1235 if (!(Section
->Characteristics
& EFI_IMAGE_SCN_MEM_READ
))
1238 if (!(Section
->Characteristics
& EFI_IMAGE_SCN_MEM_DISCARDABLE
) &&
1239 (Section
->Characteristics
& EFI_IMAGE_SCN_MEM_WRITE
) &&
1240 (Section
->Characteristics
& EFI_IMAGE_SCN_MEM_EXECUTE
) &&
1241 (mok_policy
& MOK_POLICY_REQUIRE_NX
)) {
1242 perror(L
"Section %d is writable and executable\n", i
);
1243 return EFI_UNSUPPORTED
;
1246 base
= ImageAddress (buffer
, context
.ImageSize
,
1247 Section
->VirtualAddress
);
1248 end
= ImageAddress (buffer
, context
.ImageSize
,
1249 Section
->VirtualAddress
1250 + Section
->Misc
.VirtualSize
- 1);
1253 perror(L
"Section %d has negative size\n", i
);
1254 BS
->FreePages(*alloc_address
, *alloc_pages
);
1255 return EFI_UNSUPPORTED
;
1258 if (Section
->VirtualAddress
<= context
.EntryPoint
&&
1259 (Section
->VirtualAddress
+ Section
->SizeOfRawData
- 1)
1260 > context
.EntryPoint
)
1261 found_entry_point
++;
1263 /* We do want to process .reloc, but it's often marked
1264 * discardable, so we don't want to memcpy it. */
1265 if (CompareMem(Section
->Name
, ".reloc\0\0", 8) == 0) {
1267 perror(L
"Image has multiple relocation sections\n");
1268 return EFI_UNSUPPORTED
;
1270 /* If it has nonzero sizes, and our bounds check
1271 * made sense, and the VA and size match RelocDir's
1272 * versions, then we believe in this section table. */
1273 if (Section
->SizeOfRawData
&&
1274 Section
->Misc
.VirtualSize
&&
1276 RelocBase
== base
&&
1277 RelocBaseEnd
== end
) {
1278 RelocSection
= Section
;
1282 if (Section
->Characteristics
& EFI_IMAGE_SCN_MEM_DISCARDABLE
) {
1287 perror(L
"Section %d has invalid base address\n", i
);
1288 return EFI_UNSUPPORTED
;
1291 perror(L
"Section %d has zero size\n", i
);
1292 return EFI_UNSUPPORTED
;
1295 if (!(Section
->Characteristics
& EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA
) &&
1296 (Section
->VirtualAddress
< context
.SizeOfHeaders
||
1297 Section
->PointerToRawData
< context
.SizeOfHeaders
)) {
1298 perror(L
"Section %d is inside image headers\n", i
);
1299 return EFI_UNSUPPORTED
;
1302 if (Section
->Characteristics
& EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA
) {
1303 ZeroMem(base
, Section
->Misc
.VirtualSize
);
1305 if (Section
->PointerToRawData
< context
.SizeOfHeaders
) {
1306 perror(L
"Section %d is inside image headers\n", i
);
1307 return EFI_UNSUPPORTED
;
1310 size
= Section
->Misc
.VirtualSize
;
1311 if (size
> Section
->SizeOfRawData
)
1312 size
= Section
->SizeOfRawData
;
1315 CopyMem(base
, data
+ Section
->PointerToRawData
, size
);
1317 if (size
< Section
->Misc
.VirtualSize
)
1318 ZeroMem(base
+ size
, Section
->Misc
.VirtualSize
- size
);
1322 if (context
.NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1323 perror(L
"Image has no relocation entry\n");
1325 return EFI_UNSUPPORTED
;
1328 if (context
.RelocDir
->Size
&& RelocSection
) {
1330 * Run the relocation fixups
1332 efi_status
= relocate_coff(&context
, RelocSection
, data
,
1335 if (EFI_ERROR(efi_status
)) {
1336 perror(L
"Relocation failed: %r\n", efi_status
);
1343 * Now set the page permissions appropriately.
1345 Section
= context
.FirstSection
;
1346 for (i
= 0; i
< context
.NumberOfSections
; i
++, Section
++) {
1347 uint64_t set_attrs
= MEM_ATTR_R
;
1348 uint64_t clear_attrs
= MEM_ATTR_W
|MEM_ATTR_X
;
1353 * Skip discardable sections with zero size
1355 if ((Section
->Characteristics
& EFI_IMAGE_SCN_MEM_DISCARDABLE
) &&
1356 !Section
->Misc
.VirtualSize
)
1360 * Skip sections that aren't marked readable.
1362 if (!(Section
->Characteristics
& EFI_IMAGE_SCN_MEM_READ
))
1365 base
= ImageAddress (buffer
, context
.ImageSize
,
1366 Section
->VirtualAddress
);
1367 end
= ImageAddress (buffer
, context
.ImageSize
,
1368 Section
->VirtualAddress
1369 + Section
->Misc
.VirtualSize
- 1);
1371 addr
= (uintptr_t)base
;
1372 length
= (uintptr_t)end
- (uintptr_t)base
+ 1;
1374 if (Section
->Characteristics
& EFI_IMAGE_SCN_MEM_WRITE
) {
1375 set_attrs
|= MEM_ATTR_W
;
1376 clear_attrs
&= ~MEM_ATTR_W
;
1378 if (Section
->Characteristics
& EFI_IMAGE_SCN_MEM_EXECUTE
) {
1379 set_attrs
|= MEM_ATTR_X
;
1380 clear_attrs
&= ~MEM_ATTR_X
;
1382 update_mem_attrs(addr
, length
, set_attrs
, clear_attrs
);
1387 * grub needs to know its location and size in memory, so fix up
1388 * the loaded image protocol values
1390 li
->ImageBase
= buffer
;
1391 li
->ImageSize
= context
.ImageSize
;
1393 /* Pass the load options to the second stage loader */
1394 li
->LoadOptions
= load_options
;
1395 li
->LoadOptionsSize
= load_options_size
;
1397 if (!found_entry_point
) {
1398 perror(L
"Entry point is not within sections\n");
1399 return EFI_UNSUPPORTED
;
1401 if (found_entry_point
> 1) {
1402 perror(L
"%d sections contain entry point\n", found_entry_point
);
1403 return EFI_UNSUPPORTED
;
1409 // vim:fenc=utf-8:tw=75:noet