OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
ImageLoader.c
Go to the documentation of this file.
1
16
17#include <Protocol/DevicePath.h>
18#include <Protocol/LoadedImage.h>
19#include <Protocol/SimpleFileSystem.h>
20
21#include <Guid/AppleVariable.h>
22#include <Guid/FileInfo.h>
23#include <Guid/GlobalVariable.h>
24#include <Guid/OcVariable.h>
25
27
28#include <Library/BaseLib.h>
29#include <Library/BaseMemoryLib.h>
31#include <Library/DevicePathLib.h>
32#include <Library/MemoryAllocationLib.h>
33#include <Library/MemoryAllocationLibEx.h>
38#include <Library/OcFileLib.h>
39#include <Library/OcMachoLib.h>
40#include <Library/OcMiscLib.h>
42#include <Library/OcStringLib.h>
43#include <Library/UefiImageLib.h>
44#include <Library/UefiBootServicesTableLib.h>
45#include <Library/UefiLib.h>
46#include <Library/UefiRuntimeServicesTableLib.h>
47#include <Library/PrintLib.h>
48
49#if defined (MDE_CPU_IA32)
50#define OC_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_I386
51#elif defined (MDE_CPU_X64)
52#define OC_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_X64
53#else
54 #error Unsupported architecture.
55#endif
56
57STATIC EFI_GUID mOcLoadedImageProtocolGuid = {
58 0x1f3c963d, 0xf9dc, 0x4537, { 0xbb, 0x06, 0xd8, 0x08, 0x46, 0x4a, 0x85, 0x2e }
59};
60
62 0xf5bbca36, 0x0f99, 0x4e7b, { 0x86, 0x0f, 0x92, 0x06, 0xa9, 0x3b, 0x52, 0xd0 }
63};
64
65typedef struct {
66 EFI_IMAGE_ENTRY_POINT EntryPoint;
67 EFI_PHYSICAL_ADDRESS ImageArea;
68 UINTN PageCount;
69 EFI_STATUS Status;
71 BASE_LIBRARY_JUMP_BUFFER *JumpContext;
72 CHAR16 *ExitData;
74 UINT16 Subsystem;
75 BOOLEAN Started;
76 EFI_LOADED_IMAGE_PROTOCOL LoadedImage;
78
79typedef struct {
80 UINT32 ImageCaps;
82
83STATIC EFI_IMAGE_LOAD mOriginalEfiLoadImage;
84STATIC EFI_IMAGE_START mOriginalEfiStartImage;
85STATIC EFI_IMAGE_UNLOAD mOriginalEfiUnloadImage;
86STATIC EFI_EXIT mOriginalEfiExit;
87STATIC EFI_HANDLE mCurrentImageHandle;
88
91STATIC BOOLEAN mImageLoaderEnabled;
92
93STATIC BOOLEAN mProtectUefiServices;
94STATIC BOOLEAN mFixupAppleEfiImages;
95
96STATIC EFI_IMAGE_LOAD mPreservedLoadImage;
97STATIC EFI_IMAGE_START mPreservedStartImage;
98STATIC EFI_EXIT_BOOT_SERVICES mPreservedExitBootServices;
99STATIC EFI_EXIT mPreservedExit;
100
101STATIC
102VOID
104 VOID
105 )
106{
108 return;
109 }
110
111 mPreservedLoadImage = gBS->LoadImage;
112 mPreservedStartImage = gBS->StartImage;
113 mPreservedExitBootServices = gBS->ExitBootServices;
114 mPreservedExit = gBS->Exit;
115}
116
117//
118// REF: https://github.com/acidanthera/bugtracker/issues/1874
119//
120STATIC
121VOID
123 IN CONST CHAR8 *Caller
124 )
125{
127 return;
128 }
129
130 if ((gBS->LoadImage != mPreservedLoadImage) ||
131 (gBS->StartImage != mPreservedStartImage) ||
132 (gBS->ExitBootServices != mPreservedExitBootServices) ||
133 (gBS->Exit != mPreservedExit))
134 {
135 DEBUG ((
136 DEBUG_INFO,
137 "OCB: Restoring trashed L:%u S:%u EBS:%u E:%u after %a\n",
138 gBS->LoadImage != mPreservedLoadImage,
139 gBS->StartImage != mPreservedStartImage,
140 gBS->ExitBootServices != mPreservedExitBootServices,
141 gBS->Exit != mPreservedExit,
142 Caller
143 ));
144
145 gBS->LoadImage = mPreservedLoadImage;
146 gBS->StartImage = mPreservedStartImage;
147 gBS->ExitBootServices = mPreservedExitBootServices;
148 gBS->Exit = mPreservedExit;
149 }
150}
151
152STATIC
153EFI_STATUS
155 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
156 OUT UINTN *FileSize,
157 OUT VOID **FileBuffer
158 )
159{
160 EFI_STATUS Status;
161 EFI_FILE_PROTOCOL *File;
162 VOID *Buffer;
163 UINT32 Size;
164
165 Status = OcOpenFileByDevicePath (
166 &DevicePath,
167 &File,
168 EFI_FILE_MODE_READ,
169 0
170 );
171 if (EFI_ERROR (Status)) {
172 return EFI_NOT_FOUND;
173 }
174
175 Status = OcGetFileSize (
176 File,
177 &Size
178 );
179 if (EFI_ERROR (Status) || (Size == 0)) {
180 File->Close (File);
181 return EFI_UNSUPPORTED;
182 }
183
184 Buffer = AllocatePool (Size);
185 if (Buffer == NULL) {
186 File->Close (File);
187 return EFI_OUT_OF_RESOURCES;
188 }
189
190 Status = OcGetFileData (
191 File,
192 0,
193 Size,
194 Buffer
195 );
196 if (EFI_ERROR (Status)) {
197 FreePool (Buffer);
198 File->Close (File);
199 return EFI_DEVICE_ERROR;
200 }
201
202 *FileBuffer = Buffer;
203 *FileSize = Size;
204 return EFI_SUCCESS;
205}
206
207STATIC
208EFI_STATUS
210 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
211 IN BOOLEAN UseLoadImage2,
212 OUT UINTN *FileSize,
213 OUT VOID **FileBuffer
214 )
215{
216 //
217 // TODO: Implement image load protocol if necessary.
218 //
219 return EFI_UNSUPPORTED;
220}
221
222STATIC
223EFI_STATUS
225 IN EFI_HANDLE ImageHandle,
226 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
227 )
228{
229 EFI_STATUS Status;
230 EFI_HANDLE DeviceHandle;
231 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
232 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
233
234 Status = gBS->HandleProtocol (
235 ImageHandle,
237 (VOID **)&LoadedImage
238 );
239 if (EFI_ERROR (Status)) {
240 return Status;
241 }
242
243 RemainingDevicePath = DevicePath;
244 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &RemainingDevicePath, &DeviceHandle);
245 if (EFI_ERROR (Status)) {
246 //
247 // TODO: Handle load protocol if necessary.
248 //
249 return Status;
250 }
251
252 if (LoadedImage->DeviceHandle != DeviceHandle) {
253 LoadedImage->DeviceHandle = DeviceHandle;
254 LoadedImage->FilePath = DuplicateDevicePath (RemainingDevicePath);
255 }
256
257 return EFI_SUCCESS;
258}
259
260EFI_STATUS
261EFIAPI
263 IN BOOLEAN BootPolicy,
264 IN EFI_HANDLE ParentImageHandle,
265 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
266 IN VOID *SourceBuffer OPTIONAL,
267 IN UINTN SourceSize,
268 OUT EFI_HANDLE *ImageHandle
269 )
270{
271 EFI_STATUS Status;
272 EFI_STATUS ImageStatus;
273 UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext;
274 UINT32 ImageSize;
275 UINT32 DestinationSize;
276 UINT32 DestinationPages;
277 UINT32 DestinationAlignment;
278 EFI_PHYSICAL_ADDRESS DestinationArea;
279 VOID *DestinationBuffer;
280 OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
281 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
282
283 ASSERT (SourceBuffer != NULL);
284
285 //
286 // Reject very large files.
287 //
288 if (SourceSize > MAX_UINT32) {
289 return EFI_UNSUPPORTED;
290 }
291
292 //
293 // Initialize the image context.
294 //
295 ImageStatus = UefiImageInitializeContext (
296 &ImageContext,
297 SourceBuffer,
298 (UINT32)SourceSize,
299 UEFI_IMAGE_SOURCE_NON_FV,
300 UefiImageOriginUserImage
301 );
302 if (EFI_ERROR (ImageStatus)) {
303 DEBUG ((DEBUG_INFO, "OCB: PeCoff init failure - %r\n", ImageStatus));
304 return EFI_UNSUPPORTED;
305 }
306
307 if (ImageContext.FormatIndex != UefiImageFormatPe) {
308 ASSERT (FALSE);
309 }
310
311 //
312 // Reject images that are not meant for the platform's architecture.
313 //
314 if (ImageContext.Ctx.Pe.Machine != OC_IMAGE_FILE_MACHINE) {
315 DEBUG ((DEBUG_INFO, "OCB: PeCoff wrong machine - %x\n", ImageContext.Ctx.Pe.Machine));
316 return EFI_UNSUPPORTED;
317 }
318
319 //
320 // Reject RT drivers for the moment.
321 //
322 if (ImageContext.Ctx.Pe.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
323 DEBUG ((DEBUG_INFO, "OCB: PeCoff no support for RT drivers\n"));
324 return EFI_UNSUPPORTED;
325 }
326
327 ImageSize = UefiImageGetImageSize (&ImageContext);
328 DestinationPages = EFI_SIZE_TO_PAGES (ImageSize);
329 DestinationSize = EFI_PAGES_TO_SIZE (DestinationPages);
330 DestinationAlignment = UefiImageGetSegmentAlignment (&ImageContext);
331
332 if (DestinationSize >= BASE_16MB) {
333 DEBUG ((DEBUG_INFO, "OCB: PeCoff prohibits files over 16M (%u)\n", DestinationSize));
334 return RETURN_UNSUPPORTED;
335 }
336
337 //
338 // Allocate the image destination memory.
339 // FIXME: RT drivers require EfiRuntimeServicesCode.
340 //
341 Status = AllocateAlignedPagesEx (
342 AllocateAnyPages,
343 ImageContext.Ctx.Pe.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
344 ? EfiLoaderCode : EfiBootServicesCode,
345 DestinationPages,
346 DestinationAlignment,
347 &DestinationArea
348 );
349
350 if (EFI_ERROR (Status)) {
351 DEBUG ((DEBUG_INFO, "OCB: PeCoff could allocate image buffer\n"));
352 return Status;
353 }
354
355 DestinationBuffer = (VOID *)(UINTN)DestinationArea;
356
357 //
358 // Load and relocate image for execution.
359 //
360 ImageStatus = UefiImageLoadImageForExecution (
361 &ImageContext,
362 DestinationBuffer,
363 DestinationSize,
364 NULL,
365 0
366 );
367
368 if (EFI_ERROR (ImageStatus)) {
369 DEBUG ((DEBUG_INFO, "OCB: PeCoff load image for execution error - %r\n", ImageStatus));
370 FreeAlignedPages (DestinationBuffer, DestinationPages);
371 return EFI_UNSUPPORTED;
372 }
373
374 //
375 // Construct a LoadedImage protocol for the image.
376 //
377 OcLoadedImage = AllocateZeroPool (sizeof (*OcLoadedImage));
378 if (OcLoadedImage == NULL) {
379 FreeAlignedPages (DestinationBuffer, DestinationPages);
380 return EFI_OUT_OF_RESOURCES;
381 }
382
383 OcLoadedImage->EntryPoint = (EFI_IMAGE_ENTRY_POINT)((UINTN)DestinationBuffer + ImageContext.Ctx.Pe.AddressOfEntryPoint);
384 OcLoadedImage->ImageArea = DestinationArea;
385 OcLoadedImage->PageCount = DestinationPages;
386 OcLoadedImage->Subsystem = ImageContext.Ctx.Pe.Subsystem;
387
388 LoadedImage = &OcLoadedImage->LoadedImage;
389
390 LoadedImage->Revision = EFI_LOADED_IMAGE_INFORMATION_REVISION;
391 LoadedImage->ParentHandle = ParentImageHandle;
392 LoadedImage->SystemTable = gST;
393 LoadedImage->ImageBase = DestinationBuffer;
394 LoadedImage->ImageSize = DestinationSize;
395 //
396 // FIXME: Support RT drivers.
397 //
398 if (ImageContext.Ctx.Pe.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
399 LoadedImage->ImageCodeType = EfiLoaderCode;
400 LoadedImage->ImageDataType = EfiLoaderData;
401 } else {
402 LoadedImage->ImageCodeType = EfiBootServicesCode;
403 LoadedImage->ImageDataType = EfiBootServicesData;
404 }
405
406 //
407 // Install LoadedImage and the image's entry point.
408 //
409 *ImageHandle = NULL;
410 Status = gBS->InstallMultipleProtocolInterfaces (
411 ImageHandle,
413 LoadedImage,
415 OcLoadedImage,
416 NULL
417 );
418 if (EFI_ERROR (Status)) {
419 DEBUG ((DEBUG_INFO, "OCB: PeCoff proto install error - %r\n", Status));
420 FreePool (OcLoadedImage);
421 FreeAlignedPages (DestinationBuffer, DestinationPages);
422 return Status;
423 }
424
425 DEBUG ((DEBUG_VERBOSE, "OCB: Loaded image at %p\n", *ImageHandle));
426
427 return EFI_SUCCESS;
428}
429
438STATIC
439EFI_STATUS
441 IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage,
442 IN EFI_HANDLE ImageHandle
443 )
444{
445 EFI_STATUS Status;
446 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
447
448 LoadedImage = &OcLoadedImage->LoadedImage;
449 if (LoadedImage->Unload != NULL) {
450 Status = LoadedImage->Unload (ImageHandle);
451 if (EFI_ERROR (Status)) {
452 return Status;
453 }
454
455 //
456 // Do not allow to execute Unload multiple times.
457 //
458 LoadedImage->Unload = NULL;
459 } else if (OcLoadedImage->Started) {
460 return EFI_UNSUPPORTED;
461 }
462
463 Status = gBS->UninstallMultipleProtocolInterfaces (
464 ImageHandle,
466 LoadedImage,
468 OcLoadedImage,
469 NULL
470 );
471 if (EFI_ERROR (Status)) {
472 return Status;
473 }
474
475 FreeAlignedPages ((VOID *)(UINTN)OcLoadedImage->ImageArea, OcLoadedImage->PageCount);
476 FreePool (OcLoadedImage);
477 //
478 // NOTE: Avoid EFI 1.10 extension of closing opened protocols.
479 //
480 return EFI_SUCCESS;
481}
482
499STATIC
500EFI_STATUS
502 IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage,
503 IN EFI_HANDLE ImageHandle,
504 IN EFI_STATUS ExitStatus,
505 IN UINTN ExitDataSize,
506 IN CHAR16 *ExitData OPTIONAL
507 )
508{
509 EFI_TPL OldTpl;
510
511 DEBUG ((
512 DEBUG_VERBOSE,
513 "OCB: Exit %p %p (%d) - %r\n",
514 ImageHandle,
516 OcLoadedImage->Started,
517 ExitStatus
518 ));
519
520 //
521 // Prevent possible reentrance to this function for the same ImageHandle.
522 //
523 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
524
525 //
526 // If the image has not been started just free its resources.
527 // Should not happen normally.
528 //
529 if (!OcLoadedImage->Started) {
530 InternalDirectUnloadImage (OcLoadedImage, ImageHandle);
531 gBS->RestoreTPL (OldTpl);
532 return EFI_SUCCESS;
533 }
534
535 //
536 // If the image has been started, verify this image can exit.
537 //
538 if (ImageHandle != mCurrentImageHandle) {
539 DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "OCB: Image is not exitable image\n"));
540 gBS->RestoreTPL (OldTpl);
541 return EFI_INVALID_PARAMETER;
542 }
543
544 //
545 // Set the return status.
546 //
547 OcLoadedImage->Status = ExitStatus;
548
549 //
550 // If there's ExitData info provide it.
551 //
552 if (ExitData != NULL) {
553 OcLoadedImage->ExitDataSize = ExitDataSize;
554 OcLoadedImage->ExitData = AllocatePool (OcLoadedImage->ExitDataSize);
555 if (OcLoadedImage->ExitData != NULL) {
556 CopyMem (OcLoadedImage->ExitData, ExitData, OcLoadedImage->ExitDataSize);
557 } else {
558 OcLoadedImage->ExitDataSize = 0;
559 }
560 }
561
562 //
563 // return to StartImage
564 //
565 gBS->RestoreTPL (OldTpl);
566 LongJump (OcLoadedImage->JumpContext, (UINTN)-1);
567
568 //
569 // If we return from LongJump, then it is an error
570 //
571 ASSERT (FALSE);
572 CpuDeadLoop ();
573 return EFI_ACCESS_DENIED;
574}
575
587STATIC
588EFI_STATUS
590 IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage,
591 IN EFI_HANDLE ImageHandle,
592 OUT UINTN *ExitDataSize,
593 OUT CHAR16 **ExitData OPTIONAL
594 )
595{
596 EFI_STATUS Status;
597 EFI_HANDLE LastImage;
598 UINTN SetJumpFlag;
599
600 //
601 // Push the current image.
602 //
603 LastImage = mCurrentImageHandle;
604 mCurrentImageHandle = ImageHandle;
605
606 //
607 // Set long jump for Exit() support
608 // JumpContext must be aligned on a CPU specific boundary.
609 // Overallocate the buffer and force the required alignment
610 //
611 OcLoadedImage->JumpBuffer = AllocatePool (
612 sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
613 );
614 if (OcLoadedImage->JumpBuffer == NULL) {
615 //
616 // Pop the current start image context
617 //
618 mCurrentImageHandle = LastImage;
619 return EFI_OUT_OF_RESOURCES;
620 }
621
622 OcLoadedImage->JumpContext = ALIGN_POINTER (
623 OcLoadedImage->JumpBuffer,
624 BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
625 );
626
627 SetJumpFlag = SetJump (OcLoadedImage->JumpContext);
628 //
629 // The initial call to SetJump() must always return 0.
630 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
631 //
632 if (SetJumpFlag == 0) {
633 //
634 // Invoke the manually loaded image entry point.
635 //
636 DEBUG ((DEBUG_VERBOSE, "OCB: Starting image %p\n", ImageHandle));
637 OcLoadedImage->Started = TRUE;
638 OcLoadedImage->Status = OcLoadedImage->EntryPoint (
639 ImageHandle,
640 OcLoadedImage->LoadedImage.SystemTable
641 );
642 //
643 // If the image returns, exit it through Exit()
644 //
645 InternalDirectExit (OcLoadedImage, ImageHandle, OcLoadedImage->Status, 0, NULL);
646 }
647
648 FreePool (OcLoadedImage->JumpBuffer);
649
650 //
651 // Pop the current image.
652 //
653 mCurrentImageHandle = LastImage;
654
655 //
656 // NOTE: EFI 1.10 is not supported, refer to
657 // https://github.com/tianocore/edk2/blob/d8dd54f071cfd60a2dcf5426764a89cd91213420/MdeModulePkg/Core/Dxe/Image/Image.c#L1686-L1697
658 //
659
660 //
661 // Return the exit data to the caller
662 //
663 if ((ExitData != NULL) && (ExitDataSize != NULL)) {
664 *ExitDataSize = OcLoadedImage->ExitDataSize;
665 *ExitData = OcLoadedImage->ExitData;
666 } else if (OcLoadedImage->ExitData != NULL) {
667 //
668 // Caller doesn't want the exit data, free it
669 //
670 FreePool (OcLoadedImage->ExitData);
671 OcLoadedImage->ExitData = NULL;
672 }
673
674 //
675 // Save the Status because Image will get destroyed if it is unloaded.
676 //
677 Status = OcLoadedImage->Status;
678
679 //
680 // If the image returned an error, or if the image is an application
681 // unload it
682 //
683 if ( EFI_ERROR (OcLoadedImage->Status)
684 || (OcLoadedImage->Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION))
685 {
686 InternalDirectUnloadImage (OcLoadedImage, ImageHandle);
687 }
688
689 return Status;
690}
691
700STATIC
701UINT32
703 IN VOID *SourceBuffer,
704 IN UINT32 SourceSize
705 )
706{
707 BOOLEAN Exists;
708 UINT32 Result;
709
710 //
711 // Find Mac OS X version pattern.
712 // This pattern started to appear with 10.7.
713 //
714 Result = 0;
715 Exists = FindPattern (
716 (CONST UINT8 *)"Mac OS X 10.",
717 NULL,
718 L_STR_LEN ("Mac OS X 10."),
719 SourceBuffer,
720 SourceSize - sizeof (UINT32),
721 &Result
722 );
723
724 #ifdef MDE_CPU_IA32
725 //
726 // For IA32 mode the only question is whether we support K32_64.
727 // This starts with 10.7, and in theory is valid for some early
728 // developer preview 10.8 images, so simply decide on Mac OS X
729 // version pattern presence.
730 //
731 if (Exists) {
733 }
734
736 #else
737 //
738 // For X64 mode, when the pattern is found, this can be 10.7 or 10.8+.
739 // 10.7 supports K32_64 and K64, while newer versions have only K64.
740 //
741 if (Exists) {
742 if (((UINT8 *)SourceBuffer)[Result + L_STR_LEN ("Mac OS X 10.")] == '7') {
744 }
745
747 }
748
749 //
750 // The pattern is not found. This can be 10.6 or 10.4~10.5.
751 // 10.6 supports K32 and K64, while older versions have only K32.
752 // Detect 10.6 by x86_64 pattern presence.
753 //
754 Result = SourceSize / 2;
755 Exists = FindPattern (
756 (CONST UINT8 *)"x86_64",
757 NULL,
758 L_STR_SIZE ("x86_64"),
759 SourceBuffer,
760 SourceSize - sizeof (UINT32),
761 &Result
762 );
763 if (Exists) {
765 }
766
768 #endif
769}
770
771STATIC
772EFI_STATUS
773EFIAPI
775 IN BOOLEAN BootPolicy,
776 IN EFI_HANDLE ParentImageHandle,
777 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
778 IN VOID *SourceBuffer OPTIONAL,
779 IN UINTN SourceSize,
780 OUT EFI_HANDLE *ImageHandle
781 )
782{
783 EFI_STATUS SecureBootStatus;
784 EFI_STATUS FilterStatus;
785 EFI_STATUS Status;
786 VOID *AllocatedBuffer;
787 OC_IMAGE_LOADER_CAPS_PROTOCOL *OcImageLoaderCaps;
788 UINT32 RealSize;
789 UINT32 SignedFileSize;
790 BOOLEAN IsFatSlice;
791 CHAR16 *FilePath;
792 BOOLEAN FixupRequired;
793 BOOLEAN AppleBootPath;
794
795 if ((ParentImageHandle == NULL) || (ImageHandle == NULL)) {
796 return EFI_INVALID_PARAMETER;
797 }
798
799 if ((SourceBuffer == NULL) && (DevicePath == NULL)) {
800 return EFI_NOT_FOUND;
801 }
802
803 if ((SourceBuffer != NULL) && (SourceSize == 0)) {
804 return EFI_UNSUPPORTED;
805 }
806
807 OcImageLoaderCaps = NULL;
808 AllocatedBuffer = NULL;
809 if (SourceBuffer == NULL) {
810 Status = InternalEfiLoadImageFile (
811 DevicePath,
812 &SourceSize,
813 &SourceBuffer
814 );
815 if (EFI_ERROR (Status)) {
817 DevicePath,
818 BootPolicy == FALSE,
819 &SourceSize,
820 &SourceBuffer
821 );
822 }
823
824 if (!EFI_ERROR (Status)) {
825 AllocatedBuffer = SourceBuffer;
826 }
827 }
828
829 if ((DevicePath != NULL) && (SourceBuffer != NULL) && mImageLoaderEnabled) {
830 SecureBootStatus = OcAppleSecureBootVerify (
831 DevicePath,
832 SourceBuffer,
833 SourceSize
834 );
835 } else {
836 SecureBootStatus = EFI_UNSUPPORTED;
837 }
838
839 //
840 // A security violation means we should just die.
841 //
842 if (SecureBootStatus == EFI_SECURITY_VIOLATION) {
843 DEBUG ((
844 DEBUG_WARN,
845 "OCB: Apple Secure Boot prohibits this boot entry, enforcing!\n"
846 ));
847 return EFI_SECURITY_VIOLATION;
848 }
849
850 if (SourceBuffer != NULL) {
851 RealSize = (UINT32)SourceSize;
852 #ifdef MDE_CPU_IA32
853 FilterStatus = FatFilterArchitecture32 ((UINT8 **)&SourceBuffer, &RealSize);
854 #else
855 FilterStatus = FatFilterArchitecture64 ((UINT8 **)&SourceBuffer, &RealSize);
856 #endif
857
858 IsFatSlice = !EFI_ERROR (FilterStatus) && (RealSize != SourceSize) && (RealSize >= EFI_PAGE_SIZE);
859
860 if (IsFatSlice) {
861 OcImageLoaderCaps = AllocateZeroPool (sizeof (*OcImageLoaderCaps));
862 if (OcImageLoaderCaps == NULL) {
863 if (AllocatedBuffer != NULL) {
864 FreePool (AllocatedBuffer);
865 }
866
867 return EFI_OUT_OF_RESOURCES;
868 }
869
870 OcImageLoaderCaps->ImageCaps = DetectCapabilities (SourceBuffer, RealSize);
871 }
872
873 //
874 // We apply to all images (not just boot images which can be detected
875 // by using mImageLoaderConfigure != NULL as a proxy for loaded kernel
876 // support) because we need to fix up other Apple files such as apfs.efi.
877 //
879 if (SecureBootStatus == EFI_SUCCESS) {
880 DEBUG ((DEBUG_INFO, "OCB: Secure boot, fixup efi ignored\n"));
881 FixupRequired = FALSE;
882 } else if (IsFatSlice) {
883 DEBUG ((DEBUG_INFO, "OCB: Fat binary, fixup efi...\n"));
884 FixupRequired = TRUE;
885 } else {
886 AppleBootPath = FALSE;
887 if (DevicePath != NULL) {
889 DevicePath,
890 &FilePath
891 );
892 if (!EFI_ERROR (Status)) {
893 AppleBootPath = (StrCmp (FilePath, APPLE_BOOTER_DEFAULT_FILE_NAME) == 0);
894 FreePool (FilePath);
895 }
896 }
897
898 if (AppleBootPath) {
899 DEBUG ((DEBUG_INFO, "OCB: Apple booter path, fixup efi...\n"));
900 FixupRequired = TRUE;
901 } else {
902 //
903 // Overlapping sections not expected outside of fat binaries (and even then
904 // only in 32-bit slices), so verify signature allowing for W^X errors only.
905 //
906 SignedFileSize = RealSize;
907 Status = PeCoffVerifyAppleSignature (SourceBuffer, &SignedFileSize);
908 if (!EFI_ERROR (Status)) {
909 DEBUG ((
910 DEBUG_INFO,
911 "OCB: Apple signed binary %u->%u, fixup efi...\n",
912 RealSize,
913 SignedFileSize
914 ));
915 RealSize = SignedFileSize;
916 FixupRequired = TRUE;
917 } else {
918 DEBUG ((DEBUG_INFO, "OCB: Not Apple signed binary, fixup efi ignored\n"));
919 FixupRequired = FALSE;
920 }
921 }
922 }
923
924 if (FixupRequired) {
925 Status = OcPatchLegacyEfi (SourceBuffer, RealSize);
926
927 //
928 // Error can mean incompletely patched image, so we should fail.
929 // Any error not the result of incomplete patching would in general not load anyway.
930 //
931 if (EFI_ERROR (Status)) {
932 if (AllocatedBuffer != NULL) {
933 FreePool (AllocatedBuffer);
934 }
935
936 return Status;
937 }
938 }
939 }
940
941 DEBUG ((
942 DEBUG_INFO,
943 "OCB: Arch filtering %p(%u)->%p(%u) caps %u - %r\n",
944 AllocatedBuffer,
945 (UINT32)SourceSize,
946 SourceBuffer,
947 RealSize,
948 OcImageLoaderCaps == NULL ? 0 : OcImageLoaderCaps->ImageCaps,
949 FilterStatus
950 ));
951
952 if (!EFI_ERROR (FilterStatus)) {
953 SourceSize = RealSize;
954 } else if (AllocatedBuffer != NULL) {
955 SourceBuffer = NULL;
956 SourceSize = 0;
957 }
958 }
959
960 if ((SourceBuffer != NULL) && (mImageLoaderPatch != NULL)) {
962 DevicePath,
963 SourceBuffer,
964 SourceSize
965 );
966 }
967
968 //
969 // Load the image ourselves in secure boot mode.
970 //
971 if (SecureBootStatus == EFI_SUCCESS) {
972 if (SourceBuffer != NULL) {
973 Status = OcImageLoaderLoad (
974 FALSE,
975 ParentImageHandle,
976 DevicePath,
977 SourceBuffer,
978 SourceSize,
979 ImageHandle
980 );
981 } else {
982 //
983 // SecureBootStatus can be EFI_SUCCESS without a signature being
984 // verified, if SecureBootModel is Disabled and the boot file is from
985 // a DMG. This effectively just means: no more SB checks required, use
986 // our loader.
987 // SourceBuffer will be NULL if filtering for supported architecture
988 // failed.
989 // All this can't happen in a secure boot chain, and should not happen
990 // (with valid boot files) in a non-secure boot chain. But if it does,
991 // just abort.
992 //
993 Status = EFI_UNSUPPORTED;
994 }
995 } else {
997 Status = mOriginalEfiLoadImage (
998 BootPolicy,
999 ParentImageHandle,
1000 DevicePath,
1001 SourceBuffer,
1002 SourceSize,
1003 ImageHandle
1004 );
1005 RestoreGrubShimHooks ("LoadImage");
1006
1007 if (!EFI_ERROR (Status) && (OcImageLoaderCaps != NULL)) {
1008 Status = gBS->InstallMultipleProtocolInterfaces (
1009 ImageHandle,
1011 OcImageLoaderCaps,
1012 NULL
1013 );
1014 if (!EFI_ERROR (Status)) {
1015 OcImageLoaderCaps = NULL;
1016 } else {
1017 DEBUG ((DEBUG_INFO, "OCB: LoaderCaps proto install error - %r\n", Status));
1018 mOriginalEfiUnloadImage (ImageHandle);
1019 }
1020 }
1021 }
1022
1023 if (OcImageLoaderCaps != NULL) {
1024 FreePool (OcImageLoaderCaps);
1025 }
1026
1027 if (AllocatedBuffer != NULL) {
1028 FreePool (AllocatedBuffer);
1029 }
1030
1031 //
1032 // Some types of firmware may not update loaded image protocol fields correctly
1033 // when loading via source buffer. Do it here.
1034 //
1035 if (!EFI_ERROR (Status) && (SourceBuffer != NULL) && (DevicePath != NULL)) {
1036 InternalUpdateLoadedImage (*ImageHandle, DevicePath);
1037 }
1038
1039 return Status;
1040}
1041
1042STATIC
1043EFI_STATUS
1044EFIAPI
1046 IN EFI_HANDLE ImageHandle,
1047 OUT UINTN *ExitDataSize,
1048 OUT CHAR16 **ExitData OPTIONAL
1049 )
1050{
1051 EFI_STATUS Status;
1052 OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
1053 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1054 OC_IMAGE_LOADER_CAPS_PROTOCOL *OcImageLoaderCaps;
1055 UINT32 Caps;
1056
1057 //
1058 // Use target default except where we detected and saved other caps on load.
1059 //
1060 #ifdef MDE_CPU_IA32
1062 #else
1064 #endif
1065
1066 //
1067 // If we loaded the image, invoke the entry point manually.
1068 //
1069 Status = gBS->HandleProtocol (
1070 ImageHandle,
1072 (VOID **)&OcLoadedImage
1073 );
1074 if (!EFI_ERROR (Status)) {
1075 //
1076 // Call configure update for our images.
1077 //
1078 if (mImageLoaderConfigure != NULL) {
1080 &OcLoadedImage->LoadedImage,
1081 Caps
1082 );
1083 }
1084
1086 OcLoadedImage,
1087 ImageHandle,
1088 ExitDataSize,
1089 ExitData
1090 );
1091 }
1092
1093 //
1094 // Call configure update for generic images too.
1095 //
1096 if (mImageLoaderConfigure != NULL) {
1097 Status = gBS->HandleProtocol (
1098 ImageHandle,
1100 (VOID **)&LoadedImage
1101 );
1102 if (!EFI_ERROR (Status)) {
1103 Status = gBS->HandleProtocol (
1104 ImageHandle,
1106 (VOID **)&OcImageLoaderCaps
1107 );
1108 if (!EFI_ERROR (Status)) {
1109 Caps = OcImageLoaderCaps->ImageCaps;
1110 }
1111
1113 LoadedImage,
1114 Caps
1115 );
1116 }
1117 }
1118
1120 Status = mOriginalEfiStartImage (ImageHandle, ExitDataSize, ExitData);
1121 RestoreGrubShimHooks ("StartImage");
1122
1123 return Status;
1124}
1125
1126STATIC
1127EFI_STATUS
1128EFIAPI
1130 IN EFI_HANDLE ImageHandle
1131 )
1132{
1133 EFI_STATUS Status;
1134 OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
1135 OC_IMAGE_LOADER_CAPS_PROTOCOL *OcImageLoaderCaps;
1136
1137 //
1138 // If we loaded the image, do the unloading manually.
1139 //
1140 Status = gBS->HandleProtocol (
1141 ImageHandle,
1143 (VOID **)&OcLoadedImage
1144 );
1145 if (!EFI_ERROR (Status)) {
1147 OcLoadedImage,
1148 ImageHandle
1149 );
1150 }
1151
1152 //
1153 // If we saved image caps during load, free them now.
1154 //
1155 Status = gBS->HandleProtocol (
1156 ImageHandle,
1158 (VOID **)&OcImageLoaderCaps
1159 );
1160 if (!EFI_ERROR (Status)) {
1161 Status = gBS->UninstallMultipleProtocolInterfaces (
1162 ImageHandle,
1164 OcImageLoaderCaps,
1165 NULL
1166 );
1167 if (EFI_ERROR (Status)) {
1168 return Status;
1169 }
1170
1171 FreePool (OcImageLoaderCaps);
1172 }
1173
1174 return mOriginalEfiUnloadImage (ImageHandle);
1175}
1176
1177STATIC
1178EFI_STATUS
1179EFIAPI
1181 IN EFI_HANDLE ImageHandle,
1182 IN EFI_STATUS ExitStatus,
1183 IN UINTN ExitDataSize,
1184 IN CHAR16 *ExitData OPTIONAL
1185 )
1186{
1187 EFI_STATUS Status;
1188 OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage;
1189
1190 //
1191 // If we loaded the image, do the exit manually.
1192 //
1193 Status = gBS->HandleProtocol (
1194 ImageHandle,
1196 (VOID **)&OcLoadedImage
1197 );
1198
1199 DEBUG ((DEBUG_VERBOSE, "OCB: InternalEfiExit %p - %r / %r\n", ImageHandle, ExitStatus, Status));
1200
1201 if (!EFI_ERROR (Status)) {
1202 return InternalDirectExit (
1203 OcLoadedImage,
1204 ImageHandle,
1205 ExitStatus,
1206 ExitDataSize,
1207 ExitData
1208 );
1209 }
1210
1212 Status = mOriginalEfiExit (ImageHandle, ExitStatus, ExitDataSize, ExitData);
1213 RestoreGrubShimHooks ("Exit");
1214
1215 return Status;
1216}
1217
1218VOID
1220 IN CONST BOOLEAN ProtectUefiServices,
1221 IN CONST BOOLEAN FixupAppleEfiImages
1222 )
1223{
1224 mProtectUefiServices = ProtectUefiServices;
1225 mFixupAppleEfiImages = FixupAppleEfiImages;
1226
1227 mOriginalEfiLoadImage = gBS->LoadImage;
1228 mOriginalEfiStartImage = gBS->StartImage;
1229 mOriginalEfiUnloadImage = gBS->UnloadImage;
1230 mOriginalEfiExit = gBS->Exit;
1231
1232 gBS->LoadImage = InternalEfiLoadImage;
1233 gBS->StartImage = InternalEfiStartImage;
1234 gBS->UnloadImage = InternalEfiUnloadImage;
1235 gBS->Exit = InternalEfiExit;
1236
1237 gBS->Hdr.CRC32 = 0;
1238 gBS->CalculateCrc32 (gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
1239}
1240
1241VOID
1243 VOID
1244 )
1245{
1246 mImageLoaderEnabled = TRUE;
1247}
1248
1249VOID
1251 IN OC_IMAGE_LOADER_PATCH Patch OPTIONAL
1252 )
1253{
1254 mImageLoaderPatch = Patch;
1255}
1256
1257VOID
1259 IN OC_IMAGE_LOADER_CONFIGURE Configure OPTIONAL
1260 )
1261{
1262 mImageLoaderConfigure = Configure;
1263}
#define APPLE_BOOTER_DEFAULT_FILE_NAME
STATIC BOOLEAN mProtectUefiServices
Definition ImageLoader.c:93
STATIC OC_IMAGE_LOADER_CONFIGURE mImageLoaderConfigure
Definition ImageLoader.c:90
STATIC EFI_IMAGE_START mPreservedStartImage
Definition ImageLoader.c:97
VOID OcImageLoaderInit(IN CONST BOOLEAN ProtectUefiServices, IN CONST BOOLEAN FixupAppleEfiImages)
STATIC EFI_STATUS InternalEfiLoadImageFile(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT UINTN *FileSize, OUT VOID **FileBuffer)
STATIC BOOLEAN mFixupAppleEfiImages
Definition ImageLoader.c:94
STATIC EFI_IMAGE_LOAD mPreservedLoadImage
Definition ImageLoader.c:96
STATIC EFI_STATUS InternalDirectStartImage(IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage, IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL)
STATIC BOOLEAN mImageLoaderEnabled
Definition ImageLoader.c:91
EFI_STATUS EFIAPI OcImageLoaderLoad(IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle)
VOID OcImageLoaderRegisterConfigure(IN OC_IMAGE_LOADER_CONFIGURE Configure OPTIONAL)
STATIC EFI_STATUS EFIAPI InternalEfiLoadImage(IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle)
STATIC EFI_STATUS InternalUpdateLoadedImage(IN EFI_HANDLE ImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath)
STATIC EFI_IMAGE_UNLOAD mOriginalEfiUnloadImage
Definition ImageLoader.c:85
VOID OcImageLoaderActivate(VOID)
STATIC EFI_IMAGE_START mOriginalEfiStartImage
Definition ImageLoader.c:84
STATIC EFI_GUID mOcLoadedImageProtocolGuid
Definition ImageLoader.c:57
STATIC EFI_STATUS InternalDirectExit(IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage, IN EFI_HANDLE ImageHandle, IN EFI_STATUS ExitStatus, IN UINTN ExitDataSize, IN CHAR16 *ExitData OPTIONAL)
STATIC OC_IMAGE_LOADER_PATCH mImageLoaderPatch
Definition ImageLoader.c:89
STATIC EFI_EXIT mPreservedExit
Definition ImageLoader.c:99
STATIC VOID PreserveGrubShimHooks(VOID)
STATIC EFI_STATUS EFIAPI InternalEfiExit(IN EFI_HANDLE ImageHandle, IN EFI_STATUS ExitStatus, IN UINTN ExitDataSize, IN CHAR16 *ExitData OPTIONAL)
STATIC VOID RestoreGrubShimHooks(IN CONST CHAR8 *Caller)
STATIC EFI_STATUS EFIAPI InternalEfiUnloadImage(IN EFI_HANDLE ImageHandle)
STATIC EFI_IMAGE_LOAD mOriginalEfiLoadImage
Definition ImageLoader.c:83
STATIC EFI_HANDLE mCurrentImageHandle
Definition ImageLoader.c:87
STATIC EFI_STATUS EFIAPI InternalEfiStartImage(IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL)
STATIC EFI_EXIT_BOOT_SERVICES mPreservedExitBootServices
Definition ImageLoader.c:98
STATIC UINT32 DetectCapabilities(IN VOID *SourceBuffer, IN UINT32 SourceSize)
VOID OcImageLoaderRegisterPatch(IN OC_IMAGE_LOADER_PATCH Patch OPTIONAL)
STATIC EFI_STATUS InternalEfiLoadImageProtocol(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN BOOLEAN UseLoadImage2, OUT UINTN *FileSize, OUT VOID **FileBuffer)
STATIC EFI_GUID mOcImageLoaderCapsProtocolGuid
Definition ImageLoader.c:61
STATIC EFI_EXIT mOriginalEfiExit
Definition ImageLoader.c:86
STATIC EFI_STATUS InternalDirectUnloadImage(IN OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage, IN EFI_HANDLE ImageHandle)
EFI_STATUS OcBootPolicyDevicePathToFilePath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT CHAR16 **BootPathName)
DMG_FILEPATH_DEVICE_PATH FilePath
DMG_SIZE_DEVICE_PATH Size
EFI_STATUS OcAppleSecureBootVerify(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN VOID *SourceBuffer, IN UINTN SourceSize)
#define OC_KERN_CAPABILITY_K64_U64
Supports K64 and U64 (10.6+)
VOID(* OC_IMAGE_LOADER_CONFIGURE)(IN OUT EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, IN UINT32 Capabilities)
#define OC_KERN_CAPABILITY_K32_U64
Supports K32 and U64 (10.4~10.7)
VOID(* OC_IMAGE_LOADER_PATCH)(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, IN VOID *SourceBuffer, IN UINTN SourceSize)
#define OC_KERN_CAPABILITY_K32_U32
Supports K32 and U32 (10.4~10.6)
EFI_SYSTEM_TABLE * gST
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI OcOpenFileByDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, OUT EFI_FILE_PROTOCOL **File, IN UINT64 OpenMode, IN UINT64 Attributes)
Definition OpenFile.c:206
EFI_STATUS OcGetFileSize(IN EFI_FILE_PROTOCOL *File, OUT UINT32 *Size)
EFI_STATUS OcGetFileData(IN EFI_FILE_PROTOCOL *File, IN UINT32 Position, IN UINT32 Size, OUT UINT8 *Buffer)
EFI_STATUS FatFilterArchitecture64(IN OUT UINT8 **FileData, IN OUT UINT32 *FileSize)
Definition MachoFat.c:151
EFI_STATUS FatFilterArchitecture32(IN OUT UINT8 **FileData, IN OUT UINT32 *FileSize)
Definition MachoFat.c:142
BOOLEAN FindPattern(IN CONST UINT8 *Pattern, IN CONST UINT8 *PatternMask OPTIONAL, IN CONST UINT32 PatternSize, IN CONST UINT8 *Data, IN UINT32 DataSize, IN OUT UINT32 *DataOff)
Definition DataPatcher.c:82
EFI_STATUS PeCoffVerifyAppleSignature(IN OUT VOID *PeImage, IN OUT UINT32 *ImageSize)
EFI_STATUS OcPatchLegacyEfi(IN VOID *DriverBuffer, IN UINT32 DriverSize)
#define L_STR_LEN(String)
Definition OcStringLib.h:26
#define L_STR_SIZE(String)
Definition OcStringLib.h:35
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
EFI_GUID gEfiSimpleFileSystemProtocolGuid
EFI_GUID gEfiLoadedImageProtocolGuid
#define ASSERT(x)
Definition coder.h:55
BASE_LIBRARY_JUMP_BUFFER * JumpContext
Definition ImageLoader.c:71
EFI_IMAGE_ENTRY_POINT EntryPoint
Definition ImageLoader.c:66
EFI_PHYSICAL_ADDRESS ImageArea
Definition ImageLoader.c:67
EFI_LOADED_IMAGE_PROTOCOL LoadedImage
Definition ImageLoader.c:76