OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcPeCoffFixupInit.c
Go to the documentation of this file.
1
19#include <Base.h>
20#include <Uefi/UefiBaseType.h>
21
22#include <IndustryStandard/PeImage2.h>
23
24#include <Guid/WinCertificate.h>
25
26#include <Library/BaseMemoryLib.h>
27#include <Library/BaseOverflowLib.h>
28#include <Library/DebugLib.h>
29#include <Library/PcdLib.h>
30#include <Library/PeCoffLib2.h>
31#include <Library/OcStringLib.h>
32
34
35//
36// FIXME: Provide an API to destruct the context?
37//
38
59STATIC
60RETURN_STATUS
62 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
63 IN UINT32 FileSize,
64 OUT UINT32 *StartAddress,
65 IN BOOLEAN InMemoryFixup
66 )
67{
68 BOOLEAN Overflow;
69 UINT32 NextSectRva;
70 UINT32 FixupOffset;
71 UINT32 PreFixupVirtualAddress;
72 UINT32 PostFixupVirtualAddress;
73 UINT32 PreFixupVirtualSize;
74 UINT32 PostFixupVirtualSize;
75 CHAR8 SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME + 1];
76 UINT32 SectRawEnd;
77 UINT16 SectionIndex;
78 EFI_IMAGE_SECTION_HEADER *Sections;
79
80 ASSERT (Context != NULL);
81 ASSERT (IS_POW2 (Context->SectionAlignment));
82 ASSERT (StartAddress != NULL);
83 //
84 // Images without Sections have no usable data, disallow them.
85 //
86 if (Context->NumberOfSections == 0) {
87 DEBUG_RAISE ();
88 return RETURN_VOLUME_CORRUPTED;
89 }
90
91 Sections = (EFI_IMAGE_SECTION_HEADER *)(VOID *)(
92 (CHAR8 *)Context->FileBuffer + Context->SectionsOffset
93 );
94 //
95 // The first Image section must begin the Image memory space, or it must be
96 // adjacent to the Image Headers.
97 //
98 if (Sections[0].VirtualAddress == 0) {
99 // FIXME: Add PCD to disallow.
100 NextSectRva = 0;
101 } else {
102 //
103 // Choose the raw or aligned Image Headers size depending on whether loading
104 // unaligned Sections is allowed.
105 //
106 if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
107 Overflow = BaseOverflowAlignUpU32 (
108 Context->SizeOfHeaders,
109 Context->SectionAlignment,
110 &NextSectRva
111 );
112 if (Overflow) {
113 DEBUG_RAISE ();
114 return RETURN_VOLUME_CORRUPTED;
115 }
116 } else {
117 NextSectRva = Context->SizeOfHeaders;
118 }
119 }
120
121 SectionName[L_STR_LEN (SectionName)] = '\0';
122 *StartAddress = NextSectRva;
123 //
124 // Verify all Image sections are valid.
125 //
126 for (SectionIndex = 0; SectionIndex < Context->NumberOfSections; ++SectionIndex) {
127 AsciiStrnCpyS (SectionName, L_STR_SIZE (SectionName), (CHAR8 *)Sections[SectionIndex].Name, EFI_IMAGE_SIZEOF_SHORT_NAME);
128 //
129 // Fix up W^X errors in memory.
130 //
131 if ((Sections[SectionIndex].Characteristics & (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_WRITE)) == (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_WRITE)) {
132 if (InMemoryFixup) {
133 Sections[SectionIndex].Characteristics &= ~EFI_IMAGE_SCN_MEM_EXECUTE;
134 }
135
136 DEBUG ((DEBUG_INFO, "OCPE: %u fixup W^X for %a\n", InMemoryFixup, SectionName));
137 }
138
139 //
140 // Verify the Image sections are disjoint (relaxed) or adjacent (strict)
141 // depending on whether unaligned Image sections may be loaded or not.
142 // Unaligned Image sections have been observed with iPXE Option ROMs and old
143 // Apple Mac OS X bootloaders.
144 //
145 PreFixupVirtualAddress = Sections[SectionIndex].VirtualAddress;
146 PostFixupVirtualAddress = PreFixupVirtualAddress;
147 PreFixupVirtualSize = Sections[SectionIndex].VirtualSize;
148 PostFixupVirtualSize = PreFixupVirtualSize;
149 if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
150 if (Sections[SectionIndex].VirtualAddress != NextSectRva) {
151 DEBUG_RAISE ();
152 return RETURN_VOLUME_CORRUPTED;
153 }
154 } else {
155 if (Sections[SectionIndex].VirtualAddress < NextSectRva) {
156 //
157 // Disallow overlap fixup unless we're ovelapping into an empty section.
158 //
159 if (Sections[SectionIndex].SizeOfRawData > 0) {
160 DEBUG_RAISE ();
161 return RETURN_VOLUME_CORRUPTED;
162 }
163
164 //
165 // Fix up section overlap errors in memory.
166 //
167 FixupOffset = NextSectRva - Sections[SectionIndex].VirtualAddress;
168 if (FixupOffset > Sections[SectionIndex].VirtualSize) {
169 PostFixupVirtualSize = 0;
170 } else {
171 PostFixupVirtualSize -= FixupOffset;
172 }
173
174 PostFixupVirtualAddress = NextSectRva;
175 if (InMemoryFixup) {
176 Sections[SectionIndex].VirtualAddress = PostFixupVirtualAddress;
177 Sections[SectionIndex].VirtualSize = PostFixupVirtualSize;
178 }
179
180 DEBUG ((
181 DEBUG_INFO,
182 "OCPE: %u fixup section overlap for %a 0x%X(0x%X)->0x%X(0x%X)\n",
183 InMemoryFixup,
184 SectionName,
185 PreFixupVirtualAddress,
186 PreFixupVirtualSize,
187 PostFixupVirtualAddress,
188 PostFixupVirtualSize
189 ));
190 }
191
192 //
193 // If the Image section address is not aligned by the Image section
194 // alignment, fall back to important architecture-specific page sizes if
195 // possible, to ensure the Image can have memory protection applied.
196 // Otherwise, report no alignment for the Image.
197 //
198 if (!IS_ALIGNED (PostFixupVirtualAddress, Context->SectionAlignment)) {
200 DEFAULT_PAGE_ALLOCATION_GRANULARITY <= RUNTIME_PAGE_ALLOCATION_GRANULARITY,
201 "This code must be adapted to consider the reversed order."
202 );
203
204 if (IS_ALIGNED (PostFixupVirtualAddress, RUNTIME_PAGE_ALLOCATION_GRANULARITY)) {
205 Context->SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
206 } else if ( (DEFAULT_PAGE_ALLOCATION_GRANULARITY < RUNTIME_PAGE_ALLOCATION_GRANULARITY)
207 && IS_ALIGNED (PostFixupVirtualAddress, DEFAULT_PAGE_ALLOCATION_GRANULARITY))
208 {
209 Context->SectionAlignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
210 } else {
211 Context->SectionAlignment = 1;
212 }
213 }
214 }
215
216 //
217 // Verify the Image sections with data are in bounds of the file buffer.
218 //
219 if (Sections[SectionIndex].SizeOfRawData > 0) {
220 Overflow = BaseOverflowAddU32 (
221 Sections[SectionIndex].PointerToRawData,
222 Sections[SectionIndex].SizeOfRawData,
223 &SectRawEnd
224 );
225 if (Overflow) {
226 DEBUG_RAISE ();
227 return RETURN_VOLUME_CORRUPTED;
228 }
229
230 if (SectRawEnd > FileSize) {
231 DEBUG_RAISE ();
232 return RETURN_VOLUME_CORRUPTED;
233 }
234 }
235
236 //
237 // Determine the end of the current Image section.
238 //
239 Overflow = BaseOverflowAddU32 (
240 PostFixupVirtualAddress,
241 PostFixupVirtualSize,
242 &NextSectRva
243 );
244 if (Overflow) {
245 DEBUG_RAISE ();
246 return RETURN_VOLUME_CORRUPTED;
247 }
248
249 //
250 // VirtualSize does not need to be aligned, so align the result if needed.
251 //
252 if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
253 Overflow = BaseOverflowAlignUpU32 (
254 NextSectRva,
255 Context->SectionAlignment,
256 &NextSectRva
257 );
258 if (Overflow) {
259 DEBUG_RAISE ();
260 return RETURN_VOLUME_CORRUPTED;
261 }
262 }
263 }
264
265 //
266 // Set SizeOfImage to the aligned end address of the last ImageSection.
267 //
268 if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
269 Context->SizeOfImage = NextSectRva;
270 } else {
271 //
272 // Because VirtualAddress is aligned by SectionAlignment for all Image
273 // sections, and they are disjoint and ordered by VirtualAddress,
274 // VirtualAddress + VirtualSize must be safe to align by SectionAlignment for
275 // all but the last Image section.
276 // Determine the strictest common alignment that the last section's end is
277 // safe to align to.
278 //
279 Overflow = BaseOverflowAlignUpU32 (
280 NextSectRva,
281 Context->SectionAlignment,
282 &Context->SizeOfImage
283 );
284 if (Overflow) {
285 Context->SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
286 Overflow = BaseOverflowAlignUpU32 (
287 NextSectRva,
288 Context->SectionAlignment,
289 &Context->SizeOfImage
290 );
291 if ( (DEFAULT_PAGE_ALLOCATION_GRANULARITY < RUNTIME_PAGE_ALLOCATION_GRANULARITY)
292 && Overflow)
293 {
294 Context->SectionAlignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
295 Overflow = BaseOverflowAlignUpU32 (
296 NextSectRva,
297 Context->SectionAlignment,
298 &Context->SizeOfImage
299 );
300 }
301
302 if (Overflow) {
303 Context->SectionAlignment = 1;
304 }
305 }
306 }
307
308 return RETURN_SUCCESS;
309}
310
325STATIC
326RETURN_STATUS
328 IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
329 IN UINT32 StartAddress
330 )
331{
332 BOOLEAN Overflow;
333 UINT32 SectRvaEnd;
334
335 ASSERT (Context != NULL);
336 ASSERT (!Context->RelocsStripped || Context->RelocDirSize == 0);
337 //
338 // If the Base Relocations have not been stripped, verify their Directory.
339 //
340 if (Context->RelocDirSize != 0) {
341 //
342 // Verify the Relocation Directory is not empty.
343 //
344 if (sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK) > Context->RelocDirSize) {
345 DEBUG_RAISE ();
346 return RETURN_VOLUME_CORRUPTED;
347 }
348
349 //
350 // Verify the Relocation Directory does not overlap with the Image Headers.
351 //
352 if (StartAddress > Context->RelocDirRva) {
353 DEBUG_RAISE ();
354 return RETURN_VOLUME_CORRUPTED;
355 }
356
357 //
358 // Verify the Relocation Directory is contained in the Image memory space.
359 //
360 Overflow = BaseOverflowAddU32 (
361 Context->RelocDirRva,
362 Context->RelocDirSize,
363 &SectRvaEnd
364 );
365 if (Overflow || (SectRvaEnd > Context->SizeOfImage)) {
366 DEBUG_RAISE ();
367 return RETURN_VOLUME_CORRUPTED;
368 }
369
370 //
371 // Verify the Relocation Directory start is sufficiently aligned.
372 //
373 if (!IS_ALIGNED (Context->RelocDirRva, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK))) {
374 DEBUG_RAISE ();
375 return RETURN_VOLUME_CORRUPTED;
376 }
377 }
378
379 //
380 // Verify the preferred Image load address is sufficiently aligned.
381 //
382 // FIXME: Only with force-aligned sections? What to do with XIP?
383 if (!IS_ALIGNED (Context->ImageBase, (UINT64)Context->SectionAlignment)) {
384 DEBUG_RAISE ();
385 return RETURN_VOLUME_CORRUPTED;
386 }
387
388 return RETURN_SUCCESS;
389}
390
407STATIC
408RETURN_STATUS
410 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
411 IN UINT32 FileSize,
412 IN BOOLEAN InMemoryFixup
413 )
414{
415 BOOLEAN Overflow;
416 CONST EFI_IMAGE_NT_HEADERS_COMMON_HDR *PeCommon;
417 CONST EFI_IMAGE_NT_HEADERS32 *Pe32;
418 CONST EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
419 CONST CHAR8 *OptHdrPtr;
420 UINT32 HdrSizeWithoutDataDir;
421 UINT32 MinSizeOfOptionalHeader;
422 UINT32 MinSizeOfHeaders;
423 CONST EFI_IMAGE_DATA_DIRECTORY *RelocDir;
424 CONST EFI_IMAGE_DATA_DIRECTORY *SecDir;
425 UINT32 SecDirEnd;
426 UINT32 NumberOfRvaAndSizes;
427 RETURN_STATUS Status;
428 UINT32 StartAddress;
429
430 ASSERT (Context != NULL);
431 ASSERT (sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) + sizeof (UINT16) <= FileSize - Context->ExeHdrOffset);
432 if (!PcdGetBool (PcdImageLoaderAllowMisalignedOffset)) {
433 ASSERT (IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR)));
434 }
435
436 //
437 // Locate the PE Optional Header.
438 //
439 OptHdrPtr = (CONST CHAR8 *)Context->FileBuffer + Context->ExeHdrOffset;
440 OptHdrPtr += sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
441
443 IS_ALIGNED (ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR), ALIGNOF (UINT16))
444 && IS_ALIGNED (sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR), ALIGNOF (UINT16)),
445 "The following operation might be an unaligned access."
446 );
447 //
448 // Determine the type of and retrieve data from the PE Optional Header.
449 // Do not retrieve SizeOfImage as the value usually does not follow the
450 // specification. Even if the value is large enough to hold the last Image
451 // section, it may not be aligned, or it may be too large. No data can
452 // possibly be loaded past the last Image section anyway.
453 //
454 switch (*(CONST UINT16 *)(CONST VOID *)OptHdrPtr) {
455 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
456 //
457 // Verify the PE32 header is in bounds of the file buffer.
458 //
459 if (sizeof (*Pe32) > FileSize - Context->ExeHdrOffset) {
460 DEBUG_RAISE ();
461 return RETURN_VOLUME_CORRUPTED;
462 }
463
464 //
465 // The PE32 header offset is always sufficiently aligned.
466 //
468 ALIGNOF (EFI_IMAGE_NT_HEADERS32) <= ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR),
469 "The following operations may be unaligned."
470 );
471 //
472 // Populate the common data with information from the Optional Header.
473 //
474 Pe32 = (CONST EFI_IMAGE_NT_HEADERS32 *)(CONST VOID *)(
475 (CONST CHAR8 *)Context->FileBuffer + Context->ExeHdrOffset
476 );
477
478 Context->ImageType = PeCoffLoaderTypePe32;
479 Context->Subsystem = Pe32->Subsystem;
480 Context->SizeOfHeaders = Pe32->SizeOfHeaders;
481 Context->ImageBase = Pe32->ImageBase;
482 Context->AddressOfEntryPoint = Pe32->AddressOfEntryPoint;
483 Context->SectionAlignment = Pe32->SectionAlignment;
484
485 RelocDir = Pe32->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
486 SecDir = Pe32->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_SECURITY;
487
488 PeCommon = &Pe32->CommonHeader;
489 NumberOfRvaAndSizes = Pe32->NumberOfRvaAndSizes;
490 HdrSizeWithoutDataDir = sizeof (EFI_IMAGE_NT_HEADERS32) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
491
492 break;
493
494 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
495 //
496 // Verify the PE32+ header is in bounds of the file buffer.
497 //
498 if (sizeof (*Pe32Plus) > FileSize - Context->ExeHdrOffset) {
499 DEBUG_RAISE ();
500 return RETURN_VOLUME_CORRUPTED;
501 }
502
503 //
504 // Verify the PE32+ header offset is sufficiently aligned.
505 //
506 if ( !PcdGetBool (PcdImageLoaderAllowMisalignedOffset)
507 && !IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS64)))
508 {
509 DEBUG_RAISE ();
510 return RETURN_VOLUME_CORRUPTED;
511 }
512
513 //
514 // Populate the common data with information from the Optional Header.
515 //
516 Pe32Plus = (CONST EFI_IMAGE_NT_HEADERS64 *)(CONST VOID *)(
517 (CONST CHAR8 *)Context->FileBuffer + Context->ExeHdrOffset
518 );
519
520 Context->ImageType = PeCoffLoaderTypePe32Plus;
521 Context->Subsystem = Pe32Plus->Subsystem;
522 Context->SizeOfHeaders = Pe32Plus->SizeOfHeaders;
523 Context->ImageBase = Pe32Plus->ImageBase;
524 Context->AddressOfEntryPoint = Pe32Plus->AddressOfEntryPoint;
525 Context->SectionAlignment = Pe32Plus->SectionAlignment;
526
527 RelocDir = Pe32Plus->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
528 SecDir = Pe32Plus->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_SECURITY;
529
530 PeCommon = &Pe32Plus->CommonHeader;
531 NumberOfRvaAndSizes = Pe32Plus->NumberOfRvaAndSizes;
532 HdrSizeWithoutDataDir = sizeof (EFI_IMAGE_NT_HEADERS64) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR);
533
534 break;
535
536 default:
537 //
538 // Disallow Images with unknown PE Optional Header signatures.
539 //
540 DEBUG_RAISE ();
541 return RETURN_UNSUPPORTED;
542 }
543
544 //
545 // Disallow Images with unknown directories.
546 //
547 if (NumberOfRvaAndSizes > EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES) {
548 DEBUG_RAISE ();
549 return RETURN_VOLUME_CORRUPTED;
550 }
551
552 //
553 // Verify the Image alignment is a power of 2.
554 //
555 if (!IS_POW2 (Context->SectionAlignment)) {
556 DEBUG_RAISE ();
557 return RETURN_VOLUME_CORRUPTED;
558 }
559
561 sizeof (EFI_IMAGE_DATA_DIRECTORY) <= MAX_UINT32 / EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
562 "The following arithmetic may overflow."
563 );
564 //
565 // Calculate the offset of the Image sections.
566 //
567 // Context->ExeHdrOffset + sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) cannot overflow because
568 // * ExeFileSize > sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) and
569 // * Context->ExeHdrOffset + ExeFileSize = FileSize
570 //
571 Overflow = BaseOverflowAddU32 (
572 Context->ExeHdrOffset + sizeof (*PeCommon),
573 PeCommon->FileHeader.SizeOfOptionalHeader,
574 &Context->SectionsOffset
575 );
576 if (Overflow) {
577 DEBUG_RAISE ();
578 return RETURN_VOLUME_CORRUPTED;
579 }
580
581 //
582 // Verify the Section Headers offset is sufficiently aligned.
583 //
584 if ( !PcdGetBool (PcdImageLoaderAllowMisalignedOffset)
585 && !IS_ALIGNED (Context->SectionsOffset, ALIGNOF (EFI_IMAGE_SECTION_HEADER)))
586 {
587 DEBUG_RAISE ();
588 return RETURN_VOLUME_CORRUPTED;
589 }
590
591 //
592 // This arithmetic cannot overflow because all values are sufficiently
593 // bounded.
594 //
595 MinSizeOfOptionalHeader = HdrSizeWithoutDataDir +
596 NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY);
597
598 ASSERT (MinSizeOfOptionalHeader >= HdrSizeWithoutDataDir);
599
601 sizeof (EFI_IMAGE_SECTION_HEADER) <= (MAX_UINT32 + 1ULL) / (MAX_UINT16 + 1ULL),
602 "The following arithmetic may overflow."
603 );
604 //
605 // Calculate the minimum size of the Image Headers.
606 //
607 Overflow = BaseOverflowAddU32 (
608 Context->SectionsOffset,
609 (UINT32)PeCommon->FileHeader.NumberOfSections * sizeof (EFI_IMAGE_SECTION_HEADER),
610 &MinSizeOfHeaders
611 );
612 if (Overflow) {
613 DEBUG_RAISE ();
614 return RETURN_VOLUME_CORRUPTED;
615 }
616
617 //
618 // Verify the Image Header sizes are sane. SizeOfHeaders contains all header
619 // components (DOS, PE Common and Optional Header).
620 //
621 if (MinSizeOfOptionalHeader > PeCommon->FileHeader.SizeOfOptionalHeader) {
622 DEBUG_RAISE ();
623 return RETURN_VOLUME_CORRUPTED;
624 }
625
626 if (MinSizeOfHeaders > Context->SizeOfHeaders) {
627 DEBUG_RAISE ();
628 return RETURN_VOLUME_CORRUPTED;
629 }
630
631 //
632 // Verify the Image Headers are in bounds of the file buffer.
633 //
634 if (Context->SizeOfHeaders > FileSize) {
635 DEBUG_RAISE ();
636 return RETURN_VOLUME_CORRUPTED;
637 }
638
639 //
640 // Populate the Image context with information from the Common Header.
641 //
642 Context->NumberOfSections = PeCommon->FileHeader.NumberOfSections;
643 Context->Machine = PeCommon->FileHeader.Machine;
644 Context->RelocsStripped =
645 (
646 PeCommon->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED
647 ) != 0;
648
649 if (EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC < NumberOfRvaAndSizes) {
650 Context->RelocDirRva = RelocDir->VirtualAddress;
651 Context->RelocDirSize = RelocDir->Size;
652
653 if (Context->RelocsStripped && (Context->RelocDirSize != 0)) {
654 DEBUG_RAISE ();
655 return RETURN_VOLUME_CORRUPTED;
656 }
657 } else {
658 ASSERT (Context->RelocDirRva == 0);
659 ASSERT (Context->RelocDirSize == 0);
660 }
661
662 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < NumberOfRvaAndSizes) {
663 Context->SecDirOffset = SecDir->VirtualAddress;
664 Context->SecDirSize = SecDir->Size;
665 //
666 // Verify the Security Directory is in bounds of the Image buffer.
667 //
668 Overflow = BaseOverflowAddU32 (
669 Context->SecDirOffset,
670 Context->SecDirSize,
671 &SecDirEnd
672 );
673 if (Overflow || (SecDirEnd > FileSize)) {
674 DEBUG_RAISE ();
675 return RETURN_VOLUME_CORRUPTED;
676 }
677
678 //
679 // Verify the Security Directory is sufficiently aligned.
680 //
681 if (!IS_ALIGNED (Context->SecDirOffset, IMAGE_CERTIFICATE_ALIGN)) {
682 DEBUG_RAISE ();
683 return RETURN_VOLUME_CORRUPTED;
684 }
685
686 //
687 // Verify the Security Directory size is sufficiently aligned, and that if
688 // it is not empty, it can fit at least one certificate.
689 //
690 if ( (Context->SecDirSize != 0)
691 && ( !IS_ALIGNED (Context->SecDirSize, IMAGE_CERTIFICATE_ALIGN)
692 || (Context->SecDirSize < sizeof (WIN_CERTIFICATE))))
693 {
694 DEBUG_RAISE ();
695 return RETURN_VOLUME_CORRUPTED;
696 }
697 } else {
698 //
699 // The Image context is zero'd on allocation.
700 //
701 ASSERT (Context->SecDirOffset == 0);
702 ASSERT (Context->SecDirSize == 0);
703 }
704
705 //
706 // Verify the Image sections are Well-formed.
707 //
708 Status = InternalVerifySections (
709 Context,
710 FileSize,
712 InMemoryFixup
713 );
714 if (Status != RETURN_SUCCESS) {
715 DEBUG_RAISE ();
716 return Status;
717 }
718
719 //
720 // Verify the entry point is in bounds of the Image buffer.
721 //
722 if (Context->AddressOfEntryPoint >= Context->SizeOfImage) {
723 DEBUG_RAISE ();
724 return RETURN_VOLUME_CORRUPTED;
725 }
726
727 //
728 // Verify the basic Relocation information is well-formed.
729 //
730 Status = InternalValidateRelocInfo (Context, StartAddress);
731 if (Status != RETURN_SUCCESS) {
732 DEBUG_RAISE ();
733 }
734
735 return Status;
736}
737
738RETURN_STATUS
740 OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
741 IN CONST VOID *FileBuffer,
742 IN UINT32 FileSize,
743 IN BOOLEAN InMemoryFixup
744 )
745{
746 RETURN_STATUS Status;
747 CONST EFI_IMAGE_DOS_HEADER *DosHdr;
748
749 #ifndef EFIUSER
750 // The only expected calling path with InMemoryFixup == FALSE is from AppleEfiSignTool.
751 ASSERT (InMemoryFixup);
752 #endif
753
754 //
755 // Failure of these asserts can be fixed if needed by not using the Pcd
756 // values above, we do not do this initially to make it simpler to compare
757 // this file with BasePeCoffLib2/PeCoffInit.c.
758 // STATIC_ASSERT not suitable here: 'not an integral constant expression'.
759 //
760 if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
761 ASSERT (FALSE);
762 }
763
764 if (PcdGetBool (PcdImageLoaderAllowMisalignedOffset)) {
765 ASSERT (FALSE);
766 }
767
768 ASSERT (Context != NULL);
769 ASSERT (FileBuffer != NULL || FileSize == 0);
770 //
771 // Initialise the Image context with 0-values.
772 //
773 ZeroMem (Context, sizeof (*Context));
774
775 Context->FileBuffer = FileBuffer;
776 Context->FileSize = FileSize;
777 //
778 // Check whether the DOS Image Header is present.
779 //
780 if ( (sizeof (*DosHdr) <= FileSize)
781 && (*(CONST UINT16 *)(CONST VOID *)FileBuffer == EFI_IMAGE_DOS_SIGNATURE))
782 {
783 DosHdr = (CONST EFI_IMAGE_DOS_HEADER *)(CONST VOID *)(
784 (CONST CHAR8 *)FileBuffer
785 );
786 //
787 // Verify the DOS Image Header and the Executable Header are in bounds of
788 // the file buffer, and that they are disjoint.
789 //
790 if ( (sizeof (EFI_IMAGE_DOS_HEADER) > DosHdr->e_lfanew)
791 || (DosHdr->e_lfanew > FileSize))
792 {
793 DEBUG_RAISE ();
794 return RETURN_VOLUME_CORRUPTED;
795 }
796
797 Context->ExeHdrOffset = DosHdr->e_lfanew;
798 //
799 // Verify the Execution Header offset is sufficiently aligned.
800 //
801 if ( !PcdGetBool (PcdImageLoaderAllowMisalignedOffset)
802 && !IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR)))
803 {
804 return RETURN_UNSUPPORTED;
805 }
806 }
807
808 //
809 // Verify the file buffer can hold a PE Common Header.
810 //
811 if (FileSize - Context->ExeHdrOffset < sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) + sizeof (UINT16)) {
812 return RETURN_UNSUPPORTED;
813 }
814
816 ALIGNOF (UINT32) <= ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR),
817 "The following access may be performed unaligned"
818 );
819 //
820 // Verify the Image Executable Header has a PE signature.
821 //
822 if (*(CONST UINT32 *)(CONST VOID *)((CONST CHAR8 *)FileBuffer + Context->ExeHdrOffset) != EFI_IMAGE_NT_SIGNATURE) {
823 return RETURN_UNSUPPORTED;
824 }
825
826 //
827 // Verify the PE Image Header is well-formed.
828 //
829 Status = InternalInitializePe (Context, FileSize, InMemoryFixup);
830 if (Status != RETURN_SUCCESS) {
831 return Status;
832 }
833
834 return RETURN_SUCCESS;
835}
UINT32 StartAddress
Definition AppleSmBios.h:45
#define IMAGE_CERTIFICATE_ALIGN
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
STATIC RETURN_STATUS InternalValidateRelocInfo(IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context, IN UINT32 StartAddress)
STATIC RETURN_STATUS InternalVerifySections(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, IN UINT32 FileSize, OUT UINT32 *StartAddress, IN BOOLEAN InMemoryFixup)
STATIC RETURN_STATUS InternalInitializePe(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, IN UINT32 FileSize, IN BOOLEAN InMemoryFixup)
RETURN_STATUS OcPeCoffFixupInitializeContext(OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, IN CONST VOID *FileBuffer, IN UINT32 FileSize, IN BOOLEAN InMemoryFixup)
#define L_STR_LEN(String)
Definition OcStringLib.h:26
#define L_STR_SIZE(String)
Definition OcStringLib.h:35
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define ASSERT(x)
Definition coder.h:55