2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/misc/image.c
5 * PURPOSE: Boot Library Image Routines
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
14 /* DATA VARIABLES ************************************************************/
16 ULONG IapAllocatedTableEntries
;
17 ULONG IapTableEntries
;
20 /* FUNCTIONS *****************************************************************/
24 _In_ PBL_IMG_FILE File
,
30 BL_FILE_INFORMATION FileInformation
;
32 /* Check if the file was memory mapped */
33 if (File
->Flags
& BL_IMG_MEMORY_FILE
)
35 /* Just read the size of the mapping */
36 Size
= File
->FileSize
;
40 /* Do file I/O to get the file size */
41 Status
= BlFileGetInformation(File
->FileId
,
43 if (!NT_SUCCESS(Status
))
48 /* We only support files less than 4GB in the Image Mapped */
49 Size
= FileInformation
.Size
;
50 if (FileInformation
.Size
> ULONG_MAX
)
52 return STATUS_NOT_SUPPORTED
;
56 /* Return the size and success */
58 return STATUS_SUCCESS
;
62 ImgpReadAtFileOffset (
63 _In_ PBL_IMG_FILE File
,
65 _In_ ULONGLONG ByteOffset
,
67 _Out_ PULONG BytesReturned
72 /* Check what if this is a mapped file or not */
73 if (File
->Flags
& BL_IMG_MEMORY_FILE
)
75 /* Check if the boundaries are within the file size */
76 if ((ByteOffset
+ Size
) <= File
->FileSize
)
78 /* Yep, copy into the caller-supplied buffer */
80 (PVOID
)((ULONG_PTR
)File
->BaseAddress
+ (ULONG_PTR
)ByteOffset
),
83 /* If caller wanted to know, return the size copied */
86 *BytesReturned
= Size
;
90 Status
= STATUS_SUCCESS
;
95 Status
= STATUS_INVALID_PARAMETER
;
100 /* Issue the file I/O instead */
101 Status
= BlFileReadAtOffsetEx(File
->FileId
,
109 /* Return the final status */
116 _In_ PWCHAR FileName
,
118 _Out_ PBL_IMG_FILE NewFile
123 ULONGLONG RemoteFileSize
;
124 PVOID RemoteFileAddress
;
127 /* First, try to see if BD has this file remotely */
128 Status
= BlBdPullRemoteFile(FileName
,
131 if (NT_SUCCESS(Status
))
133 /* Yep, get the file size and make sure it's < 4GB */
134 FileSize
= RemoteFileSize
;
135 if (RemoteFileSize
<= ULONG_MAX
)
137 /* Remember this is a memory mapped remote file */
138 NewFile
->Flags
|= (BL_IMG_MEMORY_FILE
| BL_IMG_REMOTE_FILE
);
139 NewFile
->FileSize
= FileSize
;
140 NewFile
->BaseAddress
= RemoteFileAddress
;
145 /* Use File I/O instead */
146 Status
= BlFileOpen(DeviceId
,
150 if (!NT_SUCCESS(Status
))
152 /* Bail out on failure */
156 /* Make sure nobody thinks this is a memory file */
157 NewFile
->Flags
&= ~BL_IMG_MEMORY_FILE
;
158 NewFile
->FileId
= FileId
;
161 /* Set common data for both memory and I/O based file */
162 NewFile
->Flags
|= BL_IMG_VALID_FILE
;
163 NewFile
->FileName
= FileName
;
169 _In_ PBL_IMG_FILE File
174 /* Make sure this is a valid file, otherwise no-op */
175 Status
= STATUS_SUCCESS
;
176 if (File
->Flags
& BL_IMG_VALID_FILE
)
178 /* Is this a memory mapped file? */
179 if (!(File
->Flags
& BL_IMG_MEMORY_FILE
))
181 /* Nope, close the file handle */
182 return BlFileClose(File
->FileId
);
185 /* Is this a remote file? */
186 if (File
->Flags
& BL_IMG_REMOTE_FILE
)
188 /* Then only free the memory in that scenario */
189 EfiPrintf(L
"TODO\r\n");
190 //return MmPapFreePages(File->BaseAddress, TRUE);
194 /* Return the final status */
199 BlImgUnallocateImageBuffer (
200 _In_ PVOID ImageBase
,
201 _In_ ULONG ImageSize
,
202 _In_ ULONG ImageFlags
205 EfiPrintf(L
"leaking the shit out of %p\r\n", ImageBase
);
206 return STATUS_NOT_IMPLEMENTED
;
210 BlImgAllocateImageBuffer (
211 _Inout_ PVOID
* ImageBuffer
,
212 _In_ ULONG MemoryType
,
213 _In_ ULONGLONG ImageSize
,
218 ULONGLONG Pages
, Size
;
219 PVOID MappedBase
, CurrentBuffer
;
221 PHYSICAL_ADDRESS PhysicalAddress
;
223 /* Read and reset the current buffer address */
224 CurrentBuffer
= *ImageBuffer
;
227 /* Align the image size to page */
228 Size
= ROUND_TO_PAGES(ImageSize
);
230 /* Not sure what this attribute does yet */
232 if (Flags
& BL_LOAD_IMG_UNKNOWN_BUFFER_FLAG
)
234 Attributes
= 0x10000;
237 /* Check if the caller wants a virtual buffer */
238 if (Flags
& BL_LOAD_IMG_VIRTUAL_BUFFER
)
240 /* Set the physical address to the current buffer */
241 PhysicalAddress
.QuadPart
= (ULONG_PTR
)CurrentBuffer
;
242 Pages
= Size
>> PAGE_SHIFT
;
244 /* Allocate the physical pages */
245 Status
= BlMmAllocatePhysicalPages(&PhysicalAddress
,
250 if (!NT_SUCCESS(Status
))
252 /* If that failed, remove allocation attributes */
253 PhysicalAddress
.QuadPart
= 0;
254 Attributes
&= ~BlMemoryValidAllocationAttributeMask
,
255 Status
= BlMmAllocatePhysicalPages(&PhysicalAddress
,
262 /* Check if either attempts succeeded */
263 if (!NT_SUCCESS(Status
))
268 /* Now map the physical buffer at the address requested */
269 MappedBase
= (PVOID
)PhysicalAddress
.LowPart
;
270 Status
= BlMmMapPhysicalAddressEx(&MappedBase
,
274 if (!NT_SUCCESS(Status
))
276 /* Free on failure if needed */
277 BlMmFreePhysicalPages(PhysicalAddress
);
283 /* Otherwise, allocate raw physical pages */
284 MappedBase
= CurrentBuffer
;
285 Pages
= Size
>> PAGE_SHIFT
;
286 Status
= MmPapAllocatePagesInRange(&MappedBase
,
293 if (!NT_SUCCESS(Status
))
295 /* If that failed, try without allocation attributes */
297 Attributes
&= ~BlMemoryValidAllocationAttributeMask
,
298 Status
= MmPapAllocatePagesInRange(&MappedBase
,
307 /* Check if either attempts succeeded */
308 if (!NT_SUCCESS(Status
))
314 /* Success path, returned allocated address */
315 *ImageBuffer
= MappedBase
;
316 return STATUS_SUCCESS
;
320 BlImgLoadImageWithProgress2 (
322 _In_ BL_MEMORY_TYPE MemoryType
,
323 _In_ PWCHAR FileName
,
324 _Inout_ PVOID
* MappedBase
,
325 _Inout_ PULONG MappedSize
,
326 _In_ ULONG ImageFlags
,
327 _In_ BOOLEAN ShowProgress
,
328 _Out_opt_ PUCHAR
* HashBuffer
,
329 _Out_opt_ PULONG HashSize
333 PVOID BaseAddress
, Buffer
;
334 ULONG RemainingLength
, CurrentSize
, ImageSize
, ReadSize
;
335 BOOLEAN ComputeSignature
, ComputeHash
, Completed
;
336 BL_IMG_FILE FileHandle
;
337 ULONGLONG ByteOffset
;
338 PHYSICAL_ADDRESS PhysicalAddress
;
340 /* Initialize variables */
344 RtlZeroMemory(&FileHandle
, sizeof(FileHandle
));
346 /* Check for missing parameters */
349 Status
= STATUS_INVALID_PARAMETER
;
354 Status
= STATUS_INVALID_PARAMETER
;
359 Status
= STATUS_INVALID_PARAMETER
;
363 /* Check if the image buffer is being provided */
364 if (ImageFlags
& BL_LOAD_IMG_EXISTING_BUFFER
)
366 /* An existing base must already exist */
369 Status
= STATUS_INVALID_PARAMETER
;
374 /* Check of a hash is being requested */
375 if (ImageFlags
& BL_LOAD_IMG_COMPUTE_HASH
)
377 /* Make sure we can return the hash */
380 Status
= STATUS_INVALID_PARAMETER
;
385 Status
= STATUS_INVALID_PARAMETER
;
390 /* Check for invalid combination of parameters */
391 if ((ImageFlags
& BL_LOAD_IMG_COMPUTE_HASH
) && (ImageFlags
& 0x270))
393 Status
= STATUS_INVALID_PARAMETER
;
397 /* Initialize hash if requested by caller */
403 /* Do the same for the hash size */
409 /* Open the image file */
410 Status
= ImgpOpenFile(DeviceId
, FileName
, DeviceId
, &FileHandle
);
411 if (!NT_SUCCESS(Status
))
413 EfiPrintf(L
"Error opening file: %lx\r\n", Status
);
417 /* Get the size of the image */
418 Status
= ImgpGetFileSize(&FileHandle
, &ImageSize
);
419 if (!NT_SUCCESS(Status
))
421 EfiPrintf(L
"Error getting file size: %lx\r\n", Status
);
425 /* Read the current base address */
426 BaseAddress
= *MappedBase
;
427 if (ImageFlags
& BL_LOAD_IMG_EXISTING_BUFFER
)
429 /* Check if the current buffer is too small */
430 if (*MappedSize
< ImageSize
)
432 /* Return the required size of the buffer */
433 *MappedSize
= ImageSize
;
434 Status
= STATUS_BUFFER_TOO_SMALL
;
439 /* A buffer was not provided, allocate one ourselves */
440 Status
= BlImgAllocateImageBuffer(&BaseAddress
,
446 /* Bail out if allocation failed */
447 if (!NT_SUCCESS(Status
))
452 /* Set the initial byte offset and length to read */
453 RemainingLength
= ImageSize
;
455 Buffer
= BaseAddress
;
457 /* Update the initial progress */
461 BlUtlUpdateProgress(0, &Completed
);
462 ShowProgress
&= (Completed
!= 0) - 1;
465 /* Set the chunk size for each read */
467 if (ReadSize
> ImageSize
)
469 ReadSize
= ImageSize
;
472 /* Check if we should compute hash and/or signatures */
473 ComputeSignature
= ImageFlags
& BL_LOAD_IMG_COMPUTE_SIGNATURE
;
474 if ((ComputeSignature
) || (ImageFlags
& BL_LOAD_IMG_COMPUTE_HASH
))
477 // todo: crypto is hard
480 /* Begin the read loop */
481 while (RemainingLength
)
483 /* Check if we've got more than a chunk left to read */
484 if (RemainingLength
> ReadSize
)
487 CurrentSize
= ReadSize
;
491 /* Read only what's left */
492 CurrentSize
= RemainingLength
;
496 Status
= ImgpReadAtFileOffset(&FileHandle
,
501 if (!NT_SUCCESS(Status
))
506 /* Check if we need to compute the hash of this chunk */
509 // todo: crypto is hard
512 /* Update our position and read information */
513 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CurrentSize
);
514 RemainingLength
-= CurrentSize
;
515 ByteOffset
+= CurrentSize
;
517 /* Check if we should update the progress bar */
520 /* Compute new percentage completed, check if we're done */
521 BlUtlUpdateProgress(100 - 100 * RemainingLength
/ ImageSize
,
523 ShowProgress
&= (Completed
!= 0) - 1;
527 /* Is the read fully complete? We need to finalize the hash if requested */
528 if (ComputeHash
!= RemainingLength
)
530 // todo: CRYPTO IS HARD
533 /* Success path, return back the buffer and the size of the image */
534 *MappedBase
= BaseAddress
;
535 *MappedSize
= ImageSize
;
538 /* Close the file handle */
539 ImgpCloseFile(&FileHandle
);
541 /* Check if we failed and had allocated a buffer */
542 if (!(NT_SUCCESS(Status
)) &&
544 !(ImageFlags
& BL_LOAD_IMG_EXISTING_BUFFER
))
546 /* Check what kind of buffer we had allocated */
547 if (ImageFlags
& BL_LOAD_IMG_VIRTUAL_BUFFER
)
549 /* Unmap and free the virtual buffer */
550 PhysicalAddress
.QuadPart
= (ULONG_PTR
)BaseAddress
;
551 BlMmUnmapVirtualAddressEx(BaseAddress
, ImageSize
);
552 BlMmFreePhysicalPages(PhysicalAddress
);
556 /* Free the physical buffer */
557 //MmPapFreePages(VirtualAddress, 1);
558 EfiPrintf(L
"Leaking memory\r\n");
562 /* If we hadn't gotten to 100% yet, do it now */
565 BlUtlUpdateProgress(100, &Completed
);
568 /* Return the final status */
572 PIMAGE_SECTION_HEADER
574 _In_ PVOID ImageBase
,
578 PIMAGE_SECTION_HEADER FoundSection
;
580 PIMAGE_SECTION_HEADER SectionHeader
;
581 PIMAGE_NT_HEADERS NtHeader
;
587 /* Make sure the image is valid */
588 Status
= RtlImageNtHeaderEx(0, ImageBase
, ImageSize
, &NtHeader
);
589 if (NT_SUCCESS(Status
))
591 /* Get the first section and loop through them all */
592 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
593 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
595 /* Check if this is the resource section */
596 if (!_stricmp((PCCH
)SectionHeader
->Name
, ".rsrc"))
598 /* Yep, we're done */
599 FoundSection
= SectionHeader
;
603 /* Nope, keep going */
608 /* Return the matching section */
613 BlImgQueryCodeIntegrityBootOptions (
614 _In_ PBL_LOADED_APPLICATION_ENTRY ApplicationEntry
,
615 _Out_ PBOOLEAN IntegrityChecksDisabled
,
616 _Out_ PBOOLEAN TestSigning
623 /* Check if /DISABLEINTEGRITYCHECKS is on */
624 Status
= BlGetBootOptionBoolean(ApplicationEntry
->BcdData
,
625 BcdLibraryBoolean_DisableIntegrityChecks
,
627 *IntegrityChecksDisabled
= NT_SUCCESS(Status
) && (Value
);
629 /* Check if /TESTSIGNING is on */
630 Status
= BlGetBootOptionBoolean(ApplicationEntry
->BcdData
,
631 BcdLibraryBoolean_AllowPrereleaseSignatures
,
633 *TestSigning
= NT_SUCCESS(Status
) && (Value
);
638 _In_ PVOID ImageBase
,
639 _In_ ULONG ImageSize
,
640 _In_ ULONG ImageFlags
643 /* Check for missing parameters */
644 if (!(ImageSize
) || !(ImageBase
))
647 return STATUS_INVALID_PARAMETER
;
650 /* Unallocate the image buffer */
651 return BlImgUnallocateImageBuffer(ImageBase
, ImageSize
, ImageFlags
);
656 _In_ PBL_IMG_FILE ImageFile
,
657 _In_ BL_MEMORY_TYPE MemoryType
,
658 _Inout_ PVOID
* ImageBase
,
659 _Out_opt_ PULONG ImageSize
,
660 _Inout_opt_ PVOID Hash
,
665 ULONG FileSize
, HeaderSize
;
666 BL_IMG_FILE LocalFileBuffer
;
667 PBL_IMG_FILE LocalFile
;
668 PVOID VirtualAddress
, PreferredBase
, ImageBuffer
, CertBuffer
, HashBuffer
;
669 ULONGLONG VirtualSize
;
670 PIMAGE_DATA_DIRECTORY CertDirectory
;
671 PHYSICAL_ADDRESS PhysicalAddress
;
672 PIMAGE_NT_HEADERS NtHeaders
;
673 USHORT SectionCount
, CheckSum
, PartialSum
, FinalSum
;
674 PIMAGE_SECTION_HEADER Section
;
675 ULONG_PTR EndOfHeaders
, SectionStart
, Slack
, SectionEnd
;
676 ULONG i
, SectionSize
, RawSize
, BytesRead
, RemainingLength
, Offset
, AlignSize
;
677 BOOLEAN First
, ImageHashValid
;
678 UCHAR LocalBuffer
[1024];
679 UCHAR TrustedBootInformation
[52];
680 ULONG WorkaroundForBinutils
;
682 /* Initialize locals */
683 WorkaroundForBinutils
= 0;
688 VirtualAddress
= NULL
;
690 CertDirectory
= NULL
;
694 ImageHashValid
= FALSE
;
695 RtlZeroMemory(&TrustedBootInformation
, sizeof(TrustedBootInformation
));
697 /* Get the size of the image */
698 Status
= ImgpGetFileSize(ImageFile
, &FileSize
);
699 if (!NT_SUCCESS(Status
))
701 return STATUS_FILE_INVALID
;
704 /* Allocate a flat buffer for it */
705 Status
= BlImgAllocateImageBuffer(&ImageBuffer
, BlLoaderData
, FileSize
, 0);
706 if (!NT_SUCCESS(Status
))
711 /* Read the whole file flat for now */
712 Status
= ImgpReadAtFileOffset(ImageFile
, FileSize
, 0, ImageBuffer
, NULL
);
713 if (!NT_SUCCESS(Status
))
718 /* Build a local file handle */
719 LocalFile
= &LocalFileBuffer
;
720 LocalFileBuffer
.FileName
= ImageFile
->FileName
;
721 LocalFileBuffer
.Flags
= BL_IMG_MEMORY_FILE
| BL_IMG_VALID_FILE
;
722 LocalFileBuffer
.BaseAddress
= ImageBuffer
;
723 LocalFileBuffer
.FileSize
= FileSize
;
725 /* Get the NT headers of the file */
726 Status
= RtlImageNtHeaderEx(0, ImageBuffer
, FileSize
, &NtHeaders
);
727 if (!NT_SUCCESS(Status
))
732 /* Check if we should validate the machine type */
733 if (Flags
& BL_LOAD_PE_IMG_CHECK_MACHINE
)
735 /* Is it different than our current machine type? */
737 if (NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_AMD64
)
739 if (NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_I386
)
742 /* Is it x86 (implying we are x64) ? */
743 if (NtHeaders
->FileHeader
.Machine
== IMAGE_FILE_MACHINE_I386
)
745 /* Return special error code */
746 Status
= STATUS_INVALID_IMAGE_WIN_32
;
748 else if (NtHeaders
->FileHeader
.Machine
== IMAGE_FILE_MACHINE_AMD64
)
750 /* Otherwise, it's x64 but we are x86 */
751 Status
= STATUS_INVALID_IMAGE_WIN_64
;
755 /* Or it's ARM or something... */
756 Status
= STATUS_INVALID_IMAGE_FORMAT
;
759 /* Return with the distinguished error code */
764 /* Check if we should validate the subsystem */
765 if (Flags
& BL_LOAD_PE_IMG_CHECK_SUBSYSTEM
)
767 /* It must be a Windows boot Application */
768 if (NtHeaders
->OptionalHeader
.Subsystem
!=
769 IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION
)
771 Status
= STATUS_INVALID_IMAGE_FORMAT
;
776 /* Check if we should validate the /INTEGRITYCHECK flag */
777 if (Flags
& BL_LOAD_PE_IMG_CHECK_FORCED_INTEGRITY
)
779 /* Check if it's there */
780 if (!(NtHeaders
->OptionalHeader
.DllCharacteristics
&
781 IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
))
783 /* Nope, fail otherwise */
784 Status
= STATUS_INVALID_IMAGE_FORMAT
;
789 /* Check if we should compute the image hash */
790 if ((Flags
& BL_LOAD_PE_IMG_COMPUTE_HASH
) || (Hash
))
792 EfiPrintf(L
"No hash support\r\n");
795 /* Read the current base address, if any */
796 VirtualAddress
= *ImageBase
;
798 /* Get the virtual size of the image */
799 VirtualSize
= NtHeaders
->OptionalHeader
.SizeOfImage
;
801 /* Safely align the virtual size to a page */
802 Status
= RtlULongLongAdd(VirtualSize
,
805 if (!NT_SUCCESS(Status
))
809 VirtualSize
= ALIGN_DOWN_BY(VirtualSize
, PAGE_SIZE
);
811 /* Make sure the image isn't larger than 4GB */
812 if (VirtualSize
> ULONG_MAX
)
814 Status
= STATUS_INVALID_IMAGE_FORMAT
;
818 /* Check if we have a buffer already */
819 if (Flags
& BL_LOAD_IMG_EXISTING_BUFFER
)
821 /* Check if it's too small */
822 if (*ImageSize
< VirtualSize
)
824 /* Fail, letting the caller know how big to make it */
825 *ImageSize
= VirtualSize
;
826 Status
= STATUS_BUFFER_TOO_SMALL
;
831 /* Allocate the buffer with the flags and type the caller wants */
832 Status
= BlImgAllocateImageBuffer(&VirtualAddress
,
838 /* Bail out if allocation failed, or existing buffer is too small */
839 if (!NT_SUCCESS(Status
))
844 /* Read the size of the headers */
845 HeaderSize
= NtHeaders
->OptionalHeader
.SizeOfHeaders
;
846 if (VirtualSize
< HeaderSize
)
848 /* Bail out if they're bigger than the image! */
849 Status
= STATUS_INVALID_IMAGE_FORMAT
;
853 /* Now read the header into the buffer */
854 Status
= ImgpReadAtFileOffset(LocalFile
, HeaderSize
, 0, VirtualAddress
, NULL
);
855 if (!NT_SUCCESS(Status
))
860 /* Get the NT headers of the file */
861 Status
= RtlImageNtHeaderEx(0, VirtualAddress
, HeaderSize
, &NtHeaders
);
862 if (!NT_SUCCESS(Status
))
869 /* Record how many sections we have */
870 SectionCount
= NtHeaders
->FileHeader
.NumberOfSections
;
872 /* Capture the current checksum and reset it */
873 CheckSum
= NtHeaders
->OptionalHeader
.CheckSum
;
874 NtHeaders
->OptionalHeader
.CheckSum
= 0;
876 /* Calculate the checksum of the header, and restore the original one */
877 PartialSum
= BlUtlCheckSum(0,
880 BL_UTL_CHECKSUM_COMPLEMENT
|
881 BL_UTL_CHECKSUM_USHORT_BUFFER
);
882 NtHeaders
->OptionalHeader
.CheckSum
= CheckSum
;
884 /* Record our current position (right after the headers) */
885 EndOfHeaders
= (ULONG_PTR
)VirtualAddress
+ HeaderSize
;
886 EfiPrintf(L
"here\r\n");
888 /* Get the first section and iterate through each one */
889 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
890 for (i
= 0; i
< SectionCount
; i
++)
892 /* Compute where this section starts */
893 SectionStart
= (ULONG_PTR
)VirtualAddress
+ Section
->VirtualAddress
;
895 /* Make sure that the section fits within the image */
896 if ((VirtualSize
< Section
->VirtualAddress
) ||
897 ((PVOID
)SectionStart
< VirtualAddress
))
899 EfiPrintf(L
"fail 1\r\n");
900 Status
= STATUS_INVALID_IMAGE_FORMAT
;
904 /* Check if there's slack space between header end and the section */
905 if (!(First
) && (EndOfHeaders
< SectionStart
))
908 Slack
= SectionStart
- EndOfHeaders
;
909 RtlZeroMemory((PVOID
)EndOfHeaders
, Slack
);
912 /* Get the section virtual size and the raw size */
913 SectionSize
= Section
->Misc
.VirtualSize
;
914 RawSize
= Section
->SizeOfRawData
;
916 /* Safely align the raw size by 2 */
917 Status
= RtlULongAdd(RawSize
, 1, &AlignSize
);
918 if (!NT_SUCCESS(Status
))
922 AlignSize
= ALIGN_DOWN_BY(AlignSize
, 2);
924 /* IF we don't have a virtual size, use the raw size */
927 SectionSize
= RawSize
;
930 /* If we don't have raw data, ignore the raw size */
931 if (!Section
->PointerToRawData
)
935 else if (SectionSize
< RawSize
)
937 /* And if the virtual size is smaller, use it as the final size */
938 RawSize
= SectionSize
;
941 /* Make sure that the section doesn't overflow in memory */
942 Status
= RtlULongAdd(Section
->VirtualAddress
,
945 if (!NT_SUCCESS(Status
))
947 EfiPrintf(L
"fail 21\r\n");
948 Status
= STATUS_INVALID_IMAGE_FORMAT
;
952 /* Make sure that it fits within the image */
953 if (VirtualSize
< SectionEnd
)
955 Status
= STATUS_INVALID_IMAGE_FORMAT
;
959 /* Make sure it doesn't overflow on disk */
960 Status
= RtlULongAdd(Section
->VirtualAddress
,
963 if (!NT_SUCCESS(Status
))
965 EfiPrintf(L
"fail 31\r\n");
966 Status
= STATUS_INVALID_IMAGE_FORMAT
;
970 /* Make sure that it fits within the disk image as well */
971 if (VirtualSize
< SectionEnd
)
973 Status
= STATUS_INVALID_IMAGE_FORMAT
;
977 /* So does this section have a valid size after all? */
980 /* Are we in the first iteration? */
983 /* FUCK YOU BINUTILS */
984 if ((*(PULONG
)&Section
->Name
== 'ler.') && (RawSize
< AlignSize
))
986 /* Piece of shit won't build relocations when you tell it to,
987 * either by using --emit-relocs or --dynamicbase. People online
988 * have found out that by using -pie-executable you can get this
989 * to happen, but then it turns out that the .reloc section is
990 * incorrectly sized, and results in a corrupt PE. However, they
991 * still compute the checksum using the correct value. What idiots.
993 WorkaroundForBinutils
= AlignSize
- RawSize
;
994 AlignSize
-= WorkaroundForBinutils
;
997 /* Yes, read the section data */
998 Status
= ImgpReadAtFileOffset(LocalFile
,
1000 Section
->PointerToRawData
,
1001 (PVOID
)SectionStart
,
1003 if (!NT_SUCCESS(Status
))
1008 /* Update our current offset */
1009 Offset
= AlignSize
+ Section
->PointerToRawData
;
1011 /* Update the checksum to include this section */
1012 PartialSum
= BlUtlCheckSum(PartialSum
,
1013 (PUCHAR
)SectionStart
,
1015 BL_UTL_CHECKSUM_COMPLEMENT
|
1016 BL_UTL_CHECKSUM_USHORT_BUFFER
);
1017 AlignSize
+= WorkaroundForBinutils
;
1021 /* Are we in the first iteration? */
1024 /* Is there space at the end of the section? */
1025 if (RawSize
< SectionSize
)
1027 /* Zero out the slack space that's there */
1028 Slack
= SectionSize
- RawSize
;
1029 RtlZeroMemory((PVOID
)(SectionStart
+ RawSize
), Slack
);
1032 /* Update our tail offset */
1033 EndOfHeaders
= SectionStart
+ SectionSize
;
1036 /* Move to the next section */
1040 /* Are we in the first iteration? */
1043 /* Go to the end of the file */
1044 SectionStart
= (ULONG_PTR
)VirtualAddress
+ VirtualSize
;
1046 /* Is there still some slack space left? */
1047 if (EndOfHeaders
< SectionStart
)
1050 Slack
= SectionStart
- EndOfHeaders
;
1051 RtlZeroMemory((PVOID
)EndOfHeaders
, Slack
);
1055 /* Did the first iteration complete OK? */
1056 if ((NT_SUCCESS(Status
)) && !(First
))
1058 /* Check how many non-image bytes are left in the file */
1059 RemainingLength
= FileSize
- Offset
;
1060 while (RemainingLength
)
1062 /* See if the read will fit into our local buffer */
1063 if (RemainingLength
>= sizeof(LocalBuffer
))
1066 BytesRead
= sizeof(LocalBuffer
);
1070 /* Yes, but there's less to read */
1071 BytesRead
= RemainingLength
;
1074 /* Read 1024 bytes into the local buffer */
1075 Status
= ImgpReadAtFileOffset(LocalFile
,
1080 if (!(NT_SUCCESS(Status
)) || !(BytesRead
))
1082 Status
= STATUS_FILE_INVALID
;
1086 /* Advance the offset and reduce the length */
1087 RemainingLength
-= BytesRead
;
1088 Offset
+= BytesRead
;
1090 /* Compute the checksum of this leftover space */
1091 PartialSum
= BlUtlCheckSum(PartialSum
,
1094 BL_UTL_CHECKSUM_COMPLEMENT
|
1095 BL_UTL_CHECKSUM_USHORT_BUFFER
);
1098 /* Finally, calculate the final checksum and compare it */
1099 FinalSum
= FileSize
+ PartialSum
+ WorkaroundForBinutils
;
1100 if ((FinalSum
!= CheckSum
) && (PartialSum
== 0xFFFF))
1102 /* It hit overflow, so set it to the file size */
1103 FinalSum
= FileSize
;
1106 /* If the checksum doesn't match, and caller is enforcing, bail out */
1107 if ((FinalSum
!= CheckSum
) &&
1108 !(Flags
& BL_LOAD_PE_IMG_IGNORE_CHECKSUM_MISMATCH
))
1110 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1115 /* Check if the .rsrc section should be checked with the filename */
1116 if (Flags
& BL_LOAD_PE_IMG_VALIDATE_ORIGINAL_FILENAME
)
1118 EfiPrintf(L
"Not yet supported\r\n");
1119 Status
= 0xC0430007; // STATUS_SECUREBOOT_FILE_REPLACED
1123 /* Check if we should relocate */
1124 if (!(Flags
& BL_LOAD_PE_IMG_SKIP_RELOCATIONS
))
1126 /* Check if we loaded at a different address */
1127 PreferredBase
= (PVOID
)NtHeaders
->OptionalHeader
.ImageBase
;
1128 if (VirtualAddress
!= PreferredBase
)
1130 /* Yep -- do relocations */
1131 Status
= LdrRelocateImage(VirtualAddress
,
1132 "Boot Environment Library",
1134 STATUS_UNSUCCESSFUL
,
1135 STATUS_INVALID_IMAGE_FORMAT
);
1136 if (!NT_SUCCESS(Status
))
1145 /* Check if the image hash was valid */
1146 if (!ImageHashValid
)
1148 /* Send a TPM/SI notification without a context */
1149 BlEnNotifyEvent(0x10000002, NULL
);
1152 /* Now send a TPM/SI notification with the hash of the loaded image */
1153 BlMmTranslateVirtualAddress(VirtualAddress
, &Context
.ImageBase
);
1154 Context
.HashAlgorithm
= HashAlgorithm
;
1155 Context
.HashSize
= HashSize
;
1156 Context
.FileName
= ImageFile
->FileName
;
1157 Context
.ImageSize
= VirtualSize
;
1158 Context
.HashValid
= ImageHashValid
;
1159 Context
.Hash
= Hash
;
1160 BlEnNotifyEvent(0x10000002, &Context
);
1163 /* Return the loaded address to the caller */
1164 *ImageBase
= VirtualAddress
;
1166 /* If the caller wanted the image size, return it too */
1169 *ImageSize
= VirtualSize
;
1173 /* Check if we computed the image hash OK */
1176 /* Then free the information that ImgpValidateImageHash set up */
1177 EfiPrintf(L
"leadking trusted boot\r\n");
1178 //ImgpDestroyTrustedBootInformation(&TrustedBootInformation);
1181 /* Check if we had a hash buffer */
1185 EfiPrintf(L
"Leadking hash: %p\r\n", HashBuffer
);
1186 //MmPapFreePages(HashBuffer, TRUE);
1189 /* Check if we have a certificate diretory */
1190 if ((CertBuffer
) && (CertDirectory
))
1193 BlImgUnallocateImageBuffer(CertBuffer
, CertDirectory
->Size
, 0);
1196 /* Check if we had an image buffer allocated */
1197 if ((ImageBuffer
) && (FileSize
))
1200 BlImgUnallocateImageBuffer(ImageBuffer
, FileSize
, 0);
1203 /* Check if we had a local file handle */
1207 ImgpCloseFile(LocalFile
);
1210 /* Check if this is the failure path */
1211 if (!NT_SUCCESS(Status
))
1213 /* Check if we had started mapping in the image already */
1214 if ((VirtualAddress
) && !(Flags
& BL_LOAD_PE_IMG_EXISTING_BUFFER
))
1216 /* Into a virtual buffer? */
1217 if (Flags
& BL_LOAD_PE_IMG_VIRTUAL_BUFFER
)
1219 /* Unmap and free it */
1220 BlMmUnmapVirtualAddressEx(VirtualAddress
, VirtualSize
);
1221 PhysicalAddress
.QuadPart
= (ULONG_PTR
)VirtualAddress
;
1222 BlMmFreePhysicalPages(PhysicalAddress
);
1226 /* Into a physical buffer -- free it */
1227 EfiPrintf(L
"Leaking physical pages\r\n");
1228 // MmPapFreePages(VirtualAddress, TRUE);
1233 /* Return back to caller */
1238 BlImgLoadPEImageEx (
1239 _In_ ULONG DeviceId
,
1240 _In_ BL_MEMORY_TYPE MemoryType
,
1242 _Out_ PVOID
* ImageBase
,
1243 _Out_ PULONG ImageSize
,
1248 BL_IMG_FILE ImageFile
;
1251 /* Initialize the image file structure */
1252 ImageFile
.Flags
= 0;
1253 ImageFile
.FileName
= NULL
;
1255 /* Check if the required parameter are missing */
1256 if (!(ImageBase
) || !(Path
))
1258 return STATUS_INVALID_PARAMETER
;
1261 /* If we are loading a pre-allocated image, make sure we have it */
1262 if ((Flags
& BL_LOAD_IMG_EXISTING_BUFFER
) && (!(*ImageBase
) || !(ImageSize
)))
1264 return STATUS_INVALID_PARAMETER
;
1267 /* Load the file from disk */
1268 Status
= ImgpOpenFile(DeviceId
, Path
, 0, &ImageFile
);
1269 if (NT_SUCCESS(Status
))
1271 /* If that worked, do the PE parsing */
1272 Status
= ImgpLoadPEImage(&ImageFile
,
1280 /* Close the image file and return back to caller */
1281 ImgpCloseFile(&ImageFile
);
1286 BlImgLoadBootApplication (
1287 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
1288 _Out_ PULONG AppHandle
1292 PULONGLONG AllowedList
;
1293 ULONGLONG AllowedCount
;
1294 ULONG i
, DeviceId
, ImageSize
, Flags
, ListSize
;
1295 LARGE_INTEGER Frequency
;
1296 PVOID UnlockCode
, ImageBase
;
1297 PBL_DEVICE_DESCRIPTOR Device
, BitLockerDevice
;
1299 PBL_APPLICATION_ENTRY AppEntry
;
1300 PBL_IMG_FILE ImageFile
;
1301 BOOLEAN DisableIntegrity
, TestSigning
;
1303 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry
;
1305 /* Initialize all locals */
1306 BitLockerDevice
= NULL
;
1311 ImageAppEntry
= NULL
;
1316 /* Check for "allowed in-memory settings" */
1317 Status
= BlpGetBootOptionIntegerList(BootEntry
->BcdData
,
1318 BcdLibraryIntegerList_AllowedInMemorySettings
,
1322 if (Status
== STATUS_SUCCESS
)
1324 /* Loop through the list of allowed setting */
1325 for (i
= 0; i
< AllowedCount
; i
++)
1327 /* Find the super undocumented one */
1328 if (AllowedList
[i
] == BcdLibraryInteger_UndocumentedMagic
)
1330 /* If it's present, append the current perf frequence to it */
1331 BlTimeQueryPerformanceCounter(&Frequency
);
1332 BlAppendBootOptionInteger(BootEntry
,
1333 BcdLibraryInteger_UndocumentedMagic
,
1334 Frequency
.QuadPart
);
1339 #if BL_BITLOCKER_SUPPORT
1340 /* Do bitlocker stuff */
1341 Status
= BlFveSecureBootUnlockBootDevice(BootEntry
, &BitLockerDevice
, &UnlockCode
);
1342 if (!NT_SUCCESS(Status
))
1348 /* Get the device on which this application is on*/
1349 Status
= BlGetBootOptionDevice(BootEntry
->BcdData
,
1350 BcdLibraryDevice_ApplicationDevice
,
1353 if (!NT_SUCCESS(Status
))
1358 /* Get the path of the application */
1359 Status
= BlGetBootOptionString(BootEntry
->BcdData
,
1360 BcdLibraryString_ApplicationPath
,
1362 if (!NT_SUCCESS(Status
))
1367 /* Open the device */
1368 Status
= BlpDeviceOpen(Device
,
1369 BL_DEVICE_READ_ACCESS
,
1372 if (!NT_SUCCESS(Status
))
1377 /* Check for integrity BCD options */
1378 BlImgQueryCodeIntegrityBootOptions(BootEntry
,
1383 RtlZeroMemory(&Context
, sizeof(Context
);
1384 Context
.BootEntry
= BootEntry
;
1385 BlEnNotifyEvent(0x10000003, &Context
);
1388 /* Enable signing and hashing checks if integrity is enabled */
1390 if (!DisableIntegrity
)
1395 /* Now call the PE loader to load the image */
1396 Status
= BlImgLoadPEImageEx(DeviceId
,
1403 if (!NT_SUCCESS(Status
))
1409 /* Check if we should notify the debugger of load */
1410 if (BdDebugTransitions
)
1414 Status
= BlBdInitialize();
1415 if (NT_SUCCESS(Status
))
1417 /* Check if it's enabled */
1418 if (BlBdDebuggerEnabled())
1420 /* Send it an image load notification */
1421 BdDebuggerNotPresent
= FALSE
;
1422 RtlInitUnicodeString(&PathString
, Path
);
1423 BlBdLoadImageSymbols(&PathString
, ImageBase
);
1429 #if BL_BITLOCKER_SUPPORT
1430 /* Do bitlocker stuff */
1431 Status
= BlSecureBootCheckPolicyOnFveDevice(BitLockerDevice
);
1432 if (!NT_SUCCESS(Status
))
1438 #if BL_BITLOCKER_SUPPORT
1439 /* Do bitlocker stuff */
1440 Status
= BlFveSecureBootCheckpointBootApp(BootEntry
, BitLockerDevice
, Hash
, UnlockCode
);
1441 if (!NT_SUCCESS(Status
))
1447 /* Get the BCD option size */
1448 ListSize
= BlGetBootOptionListSize(BootEntry
->BcdData
);
1450 /* Allocate an entry with all the BCD options */
1451 AppEntry
= BlMmAllocateHeap(ListSize
+ sizeof(*AppEntry
));
1454 Status
= STATUS_NO_MEMORY
;
1459 RtlZeroMemory(AppEntry
, sizeof(*AppEntry
));
1462 strcpy(AppEntry
->Signature
, "BTAPENT");
1463 AppEntry
->Guid
= BootEntry
->Guid
;
1464 AppEntry
->Flags
= BootEntry
->Flags
;
1466 /* Copy the BCD options */
1467 RtlCopyMemory(&AppEntry
->BcdData
, BootEntry
->BcdData
, ListSize
);
1469 /* Allocate the image entry */
1470 ImageAppEntry
= BlMmAllocateHeap(sizeof(*ImageAppEntry
));
1473 Status
= STATUS_NO_MEMORY
;
1478 ImageAppEntry
->ImageBase
= ImageBase
;
1479 ImageAppEntry
->ImageSize
= ImageSize
;
1480 ImageAppEntry
->AppEntry
= AppEntry
;
1482 /* Check if this is the first entry */
1483 if (!IapTableEntries
)
1485 /* Allocate two entries */
1486 IapAllocatedTableEntries
= 0;
1487 IapTableEntries
= 2;
1488 IapImageTable
= BlMmAllocateHeap(IapTableEntries
* sizeof(PVOID
));
1491 Status
= STATUS_NO_MEMORY
;
1495 /* Zero out the entries for now */
1496 RtlZeroMemory(IapImageTable
, IapTableEntries
* sizeof(PVOID
));
1499 /* Set this entry into the table */
1500 Status
= BlTblSetEntry(&IapImageTable
,
1504 TblDoNotPurgeEntry
);
1507 /* Is the device open? Close it if so */
1510 BlDeviceClose(DeviceId
);
1513 /* Is there an allocated device? Free it */
1516 BlMmFreeHeap(Device
);
1519 /* Is there an allocated path? Free it */
1525 /* Is there a bitlocker device? Free it */
1526 if (BitLockerDevice
)
1528 BlMmFreeHeap(BitLockerDevice
);
1531 /* Is there a bitlocker unlock code? Free it */
1534 BlMmFreeHeap(UnlockCode
);
1537 /* Did we succeed in creating an entry? */
1538 if (NT_SUCCESS(Status
))
1540 /* Remember there's one more in the table */
1541 IapAllocatedTableEntries
++;
1543 /* Return success */
1547 /* Did we load an image after all? */
1551 BlImgUnLoadImage(ImageBase
, ImageSize
, 0);
1554 /* Did we allocate an app entry? Free it */
1557 BlMmFreeHeap(AppEntry
);
1560 /* Do we have an image file entry? Free it */
1563 BlMmFreeHeap(ImageFile
);
1566 /* Do we no longer have a single entry in the table? */
1567 if (!(IapAllocatedTableEntries
) && (IapImageTable
))
1569 /* Free and destroy the table */
1570 BlMmFreeHeap(IapImageTable
);
1571 IapTableEntries
= 0;
1572 IapImageTable
= NULL
;
1575 /* Return the failure code */
1580 BlpPdParseReturnArguments (
1581 _In_ PBL_RETURN_ARGUMENTS ReturnArguments
1584 /* Check if any custom data was returned */
1585 if (ReturnArguments
->DataPage
== 0)
1587 /* Nope, nothing to do */
1588 return STATUS_SUCCESS
;
1591 /* Yes, we have to parse it */
1592 EfiPrintf(L
"Return arguments not supported\r\n");
1593 return STATUS_NOT_IMPLEMENTED
;
1597 ImgArchEfiStartBootApplication (
1598 _In_ PBL_APPLICATION_ENTRY AppEntry
,
1599 _In_ PVOID ImageBase
,
1600 _In_ ULONG ImageSize
,
1601 _In_ PBL_RETURN_ARGUMENTS ReturnArguments
1604 /* Not yet implemented. This is the last step! */
1605 EfiPrintf(L
"EFI APPLICATION START!!!\r\n");
1606 EfiStall(100000000);
1607 return STATUS_NOT_IMPLEMENTED
;
1611 BlImgStartBootApplication (
1612 _In_ ULONG AppHandle
,
1613 _Inout_opt_ PBL_RETURN_ARGUMENTS ReturnArguments
1616 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry
;
1617 BL_RETURN_ARGUMENTS LocalReturnArgs
;
1618 PBL_FILE_SYSTEM_ENTRY FileSystem
;
1619 PLIST_ENTRY NextEntry
, ListHead
;
1622 /* Check if we don't have an argument structure */
1623 if (!ReturnArguments
)
1625 /* Initialize a local copy and use it instead */
1626 LocalReturnArgs
.Version
= BL_RETURN_ARGUMENTS_VERSION
;
1627 LocalReturnArgs
.Status
= STATUS_SUCCESS
;
1628 LocalReturnArgs
.Flags
= 0;
1629 LocalReturnArgs
.DataPage
= 0;
1630 LocalReturnArgs
.DataSize
= 0;
1631 ReturnArguments
= &LocalReturnArgs
;
1634 /* Make sure the handle index is valid */
1635 if (IapTableEntries
<= AppHandle
)
1637 return STATUS_INVALID_PARAMETER
;
1640 /* Get the entry for this handle, making sure it exists */
1641 ImageAppEntry
= IapImageTable
[AppHandle
];
1644 return STATUS_INVALID_PARAMETER
;
1647 /* Loop the registered file systems */
1648 ListHead
= &RegisteredFileSystems
;
1649 NextEntry
= RegisteredFileSystems
.Flink
;
1650 while (NextEntry
!= ListHead
)
1652 /* Get the filesystem entry */
1653 FileSystem
= CONTAINING_RECORD(NextEntry
,
1654 BL_FILE_SYSTEM_ENTRY
,
1657 /* See if it has a purge callback */
1658 if (FileSystem
->PurgeCallback
)
1661 FileSystem
->PurgeCallback();
1664 /* Move to the next entry */
1665 NextEntry
= NextEntry
->Flink
;
1668 /* TODO -- flush the block I/O cache too */
1669 //BlockIoPurgeCache();
1671 /* Call into EFI land to start the boot application */
1672 Status
= ImgArchEfiStartBootApplication(ImageAppEntry
->AppEntry
,
1673 ImageAppEntry
->ImageBase
,
1674 ImageAppEntry
->ImageSize
,
1677 /* Parse any arguments we got on the way back */
1678 BlpPdParseReturnArguments(ReturnArguments
);
1680 #if BL_BITLOCKER_SUPPORT
1681 /* Bitlocker stuff */
1682 FvebpCheckAllPartitions(TRUE
);
1686 /* Notify a TPM/SI event */
1687 BlEnNotifyEvent(0x10000005, NULL
);
1690 /* Reset the display */
1691 BlpDisplayReinitialize();
1693 /* TODO -- reset ETW */
1694 //BlpLogInitialize();
1701 BlImgUnloadBootApplication (
1702 _In_ ULONG AppHandle
1705 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry
;
1708 /* Make sure the handle index is valid */
1709 if (IapTableEntries
<= AppHandle
)
1711 return STATUS_INVALID_PARAMETER
;
1714 /* Get the entry for this handle, making sure it exists */
1715 ImageAppEntry
= IapImageTable
[AppHandle
];
1718 return STATUS_INVALID_PARAMETER
;
1721 /* Unload the image */
1722 Status
= BlImgUnLoadImage(ImageAppEntry
->ImageBase
,
1723 ImageAppEntry
->ImageSize
,
1725 if (NT_SUCCESS(Status
))
1727 /* Normalize the success code */
1728 Status
= STATUS_SUCCESS
;
1732 /* Normalize the failure code */
1733 Status
= STATUS_MEMORY_NOT_ALLOCATED
;
1736 /* Free the entry and the image entry as well */
1737 BlMmFreeHeap(ImageAppEntry
->AppEntry
);
1738 BlMmFreeHeap(ImageAppEntry
);
1740 /* Clear the handle */
1741 IapImageTable
[AppHandle
] = NULL
;
1743 /* Free one entry */
1744 if (!(--IapAllocatedTableEntries
))
1746 /* There are no more, so get rid of the table itself */
1747 BlMmFreeHeap(IapImageTable
);
1748 IapImageTable
= NULL
;
1749 IapTableEntries
= 0;