aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c')
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c
new file mode 100644
index 000000000..6a5f4a3b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c
@@ -0,0 +1,408 @@
+/** @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 (
+ 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);
+ }
+ );
+
+ 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
+ );
+}