mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 17:09:09 +00:00 
			
		
		
		
	 1436aea4d5
			
		
	
	
		1436aea4d5
		
	
	
	
	
		
			
			REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			415 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			415 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Implement defer image load services for user identification in UEFI2.2.
 | |
| 
 | |
| Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| #include "Defer3rdPartyImageLoad.h"
 | |
| 
 | |
| //
 | |
| // The structure to save the deferred 3rd party image information.
 | |
| //
 | |
| typedef struct {
 | |
|   EFI_DEVICE_PATH_PROTOCOL    *ImageDevicePath;
 | |
|   BOOLEAN                     BootOption;
 | |
|   BOOLEAN                     Loaded;
 | |
| } DEFERRED_3RD_PARTY_IMAGE_INFO;
 | |
| 
 | |
| //
 | |
| // The table to save the deferred 3rd party image item.
 | |
| //
 | |
| typedef struct {
 | |
|   UINTN                            Count;          ///< deferred 3rd party image count
 | |
|   DEFERRED_3RD_PARTY_IMAGE_INFO    *ImageInfo;     ///< deferred 3rd party image item
 | |
| } DEFERRED_3RD_PARTY_IMAGE_TABLE;
 | |
| 
 | |
| BOOLEAN                         mImageLoadedAfterEndOfDxe = FALSE;
 | |
| BOOLEAN                         mEndOfDxe                 = FALSE;
 | |
| DEFERRED_3RD_PARTY_IMAGE_TABLE  mDeferred3rdPartyImage    = {
 | |
|   0,       // Deferred image count
 | |
|   NULL     // The deferred image info
 | |
| };
 | |
| 
 | |
| EFI_DEFERRED_IMAGE_LOAD_PROTOCOL  mDeferredImageLoad = {
 | |
|   GetDefferedImageInfo
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Return whether the file comes from FV.
 | |
| 
 | |
|   @param[in]    File    This is a pointer to the device path of the file
 | |
|                         that is being dispatched.
 | |
| 
 | |
|   @retval TRUE  File comes from FV.
 | |
|   @retval FALSE File doesn't come from FV.
 | |
| **/
 | |
| BOOLEAN
 | |
| FileFromFv (
 | |
|   IN  CONST EFI_DEVICE_PATH_PROTOCOL  *File
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_HANDLE                DeviceHandle;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
 | |
| 
 | |
|   //
 | |
|   // First check to see if File is from a Firmware Volume
 | |
|   //
 | |
|   DeviceHandle   = NULL;
 | |
|   TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
 | |
|   Status         = gBS->LocateDevicePath (
 | |
|                           &gEfiFirmwareVolume2ProtocolGuid,
 | |
|                           &TempDevicePath,
 | |
|                           &DeviceHandle
 | |
|                           );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     DeviceHandle,
 | |
|                     &gEfiFirmwareVolume2ProtocolGuid,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the deferred image which matches the device path.
 | |
| 
 | |
|   @param[in]  ImageDevicePath  A pointer to the device path of a image.
 | |
|   @param[in]  BootOption       Whether the image is a boot option.
 | |
| 
 | |
|   @return Pointer to the found deferred image or NULL if not found.
 | |
| **/
 | |
| DEFERRED_3RD_PARTY_IMAGE_INFO *
 | |
| LookupImage (
 | |
|   IN  CONST EFI_DEVICE_PATH_PROTOCOL  *ImageDevicePath,
 | |
|   IN        BOOLEAN                   BootOption
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
|   UINTN  DevicePathSize;
 | |
| 
 | |
|   DevicePathSize = GetDevicePathSize (ImageDevicePath);
 | |
| 
 | |
|   for (Index = 0; Index < mDeferred3rdPartyImage.Count; Index++) {
 | |
|     if (CompareMem (ImageDevicePath, mDeferred3rdPartyImage.ImageInfo[Index].ImageDevicePath, DevicePathSize) == 0) {
 | |
|       ASSERT (mDeferred3rdPartyImage.ImageInfo[Index].BootOption == BootOption);
 | |
|       return &mDeferred3rdPartyImage.ImageInfo[Index];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add the image info to a deferred image list.
 | |
| 
 | |
|   @param[in]  ImageDevicePath  A pointer to the device path of a image.
 | |
|   @param[in]  BootOption       Whether the image is a boot option.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| QueueImage (
 | |
|   IN  CONST EFI_DEVICE_PATH_PROTOCOL  *ImageDevicePath,
 | |
|   IN        BOOLEAN                   BootOption
 | |
|   )
 | |
| {
 | |
|   DEFERRED_3RD_PARTY_IMAGE_INFO  *ImageInfo;
 | |
| 
 | |
|   //
 | |
|   // Expand memory for the new deferred image.
 | |
|   //
 | |
|   ImageInfo = ReallocatePool (
 | |
|                 mDeferred3rdPartyImage.Count * sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO),
 | |
|                 (mDeferred3rdPartyImage.Count + 1) * sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO),
 | |
|                 mDeferred3rdPartyImage.ImageInfo
 | |
|                 );
 | |
|   if (ImageInfo == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   mDeferred3rdPartyImage.ImageInfo = ImageInfo;
 | |
| 
 | |
|   //
 | |
|   // Save the deferred image information.
 | |
|   //
 | |
|   ImageInfo                  = &mDeferred3rdPartyImage.ImageInfo[mDeferred3rdPartyImage.Count];
 | |
|   ImageInfo->ImageDevicePath = DuplicateDevicePath (ImageDevicePath);
 | |
|   if (ImageInfo->ImageDevicePath == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ImageInfo->BootOption = BootOption;
 | |
|   ImageInfo->Loaded     = FALSE;
 | |
|   mDeferred3rdPartyImage.Count++;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns information about a deferred image.
 | |
| 
 | |
|   This function returns information about a single deferred image. The deferred images are
 | |
|   numbered consecutively, starting with 0.  If there is no image which corresponds to
 | |
|   ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by
 | |
|   iteratively calling this function until EFI_NOT_FOUND is returned.
 | |
|   Image may be NULL and ImageSize set to 0 if the decision to defer execution was made
 | |
|   because of the location of the executable image, rather than its actual contents.
 | |
| 
 | |
|   @param[in]  This             Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.
 | |
|   @param[in]  ImageIndex       Zero-based index of the deferred index.
 | |
|   @param[out] ImageDevicePath  On return, points to a pointer to the device path of the image.
 | |
|                                The device path should not be freed by the caller.
 | |
|   @param[out] Image            On return, points to the first byte of the image or NULL if the
 | |
|                                image is not available. The image should not be freed by the caller
 | |
|                                unless LoadImage() has been successfully called.
 | |
|   @param[out] ImageSize        On return, the size of the image, or 0 if the image is not available.
 | |
|   @param[out] BootOption       On return, points to TRUE if the image was intended as a boot option
 | |
|                                or FALSE if it was not intended as a boot option.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Image information returned successfully.
 | |
|   @retval EFI_NOT_FOUND         ImageIndex does not refer to a valid image.
 | |
|   @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or
 | |
|                                 BootOption is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetDefferedImageInfo (
 | |
|   IN     EFI_DEFERRED_IMAGE_LOAD_PROTOCOL  *This,
 | |
|   IN     UINTN                             ImageIndex,
 | |
|   OUT EFI_DEVICE_PATH_PROTOCOL             **ImageDevicePath,
 | |
|   OUT VOID                                 **Image,
 | |
|   OUT UINTN                                *ImageSize,
 | |
|   OUT BOOLEAN                              *BootOption
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
|   UINTN  NewCount;
 | |
| 
 | |
|   if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((ImageDevicePath == NULL) || (BootOption == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove the loaded images from the defer list in the first call.
 | |
|   //
 | |
|   if (ImageIndex == 0) {
 | |
|     NewCount = 0;
 | |
|     for (Index = 0; Index < mDeferred3rdPartyImage.Count; Index++) {
 | |
|       if (!mDeferred3rdPartyImage.ImageInfo[Index].Loaded) {
 | |
|         CopyMem (
 | |
|           &mDeferred3rdPartyImage.ImageInfo[NewCount],
 | |
|           &mDeferred3rdPartyImage.ImageInfo[Index],
 | |
|           sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO)
 | |
|           );
 | |
|         NewCount++;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     mDeferred3rdPartyImage.Count = NewCount;
 | |
|   }
 | |
| 
 | |
|   if (ImageIndex >= mDeferred3rdPartyImage.Count) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the request deferred image.
 | |
|   //
 | |
|   *ImageDevicePath = mDeferred3rdPartyImage.ImageInfo[ImageIndex].ImageDevicePath;
 | |
|   *BootOption      = mDeferred3rdPartyImage.ImageInfo[ImageIndex].BootOption;
 | |
|   *Image           = NULL;
 | |
|   *ImageSize       = 0;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Callback function executed when the EndOfDxe event group is signaled.
 | |
| 
 | |
|   @param[in] Event      Event whose notification function is being invoked.
 | |
|   @param[in] Context    The pointer to the notification function's context, which
 | |
|                         is implementation-dependent.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| EndOfDxe (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   mEndOfDxe = TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Event notification for gEfiDxeSmmReadyToLockProtocolGuid event.
 | |
| 
 | |
|   This function reports failure if any deferred image is loaded before
 | |
|   this callback.
 | |
|   Platform should publish ReadyToLock protocol immediately after signaling
 | |
|   of the End of DXE Event.
 | |
| 
 | |
|   @param  Event                 The Event that is being processed, not used.
 | |
|   @param  Context               Event Context, not used.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| DxeSmmReadyToLock (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   VOID        *Interface;
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   gBS->CloseEvent (Event);
 | |
| 
 | |
|   if (mImageLoadedAfterEndOfDxe) {
 | |
|     //
 | |
|     // Platform should not dispatch the 3rd party images after signaling EndOfDxe event
 | |
|     // but before publishing DxeSmmReadyToLock protocol.
 | |
|     //
 | |
|     DEBUG ((
 | |
|       DEBUG_ERROR,
 | |
|       "[Security] 3rd party images must be dispatched after DxeSmmReadyToLock Protocol installation!\n"
 | |
|       ));
 | |
|     REPORT_STATUS_CODE (
 | |
|       EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
 | |
|       (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)
 | |
|       );
 | |
|     ASSERT (FALSE);
 | |
|     CpuDeadLoop ();
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Defer the 3rd party image load and installs Deferred Image Load Protocol.
 | |
| 
 | |
|   @param[in]  File                  This is a pointer to the device path of the file that
 | |
|                                     is being dispatched. This will optionally be used for
 | |
|                                     logging.
 | |
|   @param[in]  BootPolicy            A boot policy that was used to call LoadImage() UEFI service.
 | |
| 
 | |
|   @retval EFI_SUCCESS               The file is not 3rd party image and can be loaded immediately.
 | |
|   @retval EFI_ACCESS_DENIED         The file is 3rd party image and needs deferred.
 | |
| **/
 | |
| EFI_STATUS
 | |
| Defer3rdPartyImageLoad (
 | |
|   IN  CONST EFI_DEVICE_PATH_PROTOCOL  *File,
 | |
|   IN  BOOLEAN                         BootPolicy
 | |
|   )
 | |
| {
 | |
|   DEFERRED_3RD_PARTY_IMAGE_INFO  *ImageInfo;
 | |
| 
 | |
|   //
 | |
|   // Ignore if File is NULL.
 | |
|   //
 | |
|   if (File == NULL) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (FileFromFv (File)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   ImageInfo = LookupImage (File, BootPolicy);
 | |
| 
 | |
|   DEBUG_CODE_BEGIN ();
 | |
|   CHAR16  *DevicePathStr;
 | |
| 
 | |
|   DevicePathStr = ConvertDevicePathToText (File, FALSE, FALSE);
 | |
|   DEBUG ((
 | |
|     DEBUG_INFO,
 | |
|     "[Security] 3rd party image[%p] %s EndOfDxe: %s.\n",
 | |
|     ImageInfo,
 | |
|     mEndOfDxe ? L"can be loaded after" : L"is deferred to load before",
 | |
|     DevicePathStr
 | |
|     ));
 | |
|   if (DevicePathStr != NULL) {
 | |
|     FreePool (DevicePathStr);
 | |
|   }
 | |
| 
 | |
|   DEBUG_CODE_END ();
 | |
| 
 | |
|   if (mEndOfDxe) {
 | |
|     mImageLoadedAfterEndOfDxe = TRUE;
 | |
|     //
 | |
|     // The image might be first time loaded after EndOfDxe,
 | |
|     // So ImageInfo can be NULL.
 | |
|     //
 | |
|     if (ImageInfo != NULL) {
 | |
|       ImageInfo->Loaded = TRUE;
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     //
 | |
|     // The image might be second time loaded before EndOfDxe,
 | |
|     // So ImageInfo can be non-NULL.
 | |
|     //
 | |
|     if (ImageInfo == NULL) {
 | |
|       QueueImage (File, BootPolicy);
 | |
|     }
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Installs DeferredImageLoad Protocol and listens EndOfDxe event.
 | |
| **/
 | |
| VOID
 | |
| Defer3rdPartyImageLoadInitialize (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_HANDLE  Handle;
 | |
|   EFI_EVENT   Event;
 | |
|   VOID        *Registration;
 | |
| 
 | |
|   Handle = NULL;
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &Handle,
 | |
|                   &gEfiDeferredImageLoadProtocolGuid,
 | |
|                   &mDeferredImageLoad,
 | |
|                   NULL
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_CALLBACK,
 | |
|                   EndOfDxe,
 | |
|                   NULL,
 | |
|                   &gEfiEndOfDxeEventGroupGuid,
 | |
|                   &Event
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   EfiCreateProtocolNotifyEvent (
 | |
|     &gEfiDxeSmmReadyToLockProtocolGuid,
 | |
|     TPL_CALLBACK,
 | |
|     DxeSmmReadyToLock,
 | |
|     NULL,
 | |
|     &Registration
 | |
|     );
 | |
| }
 |