-/** @file\r
- Implement defer image load services for user identification in UEFI2.2.\r
-\r
-Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "DxeDeferImageLoadLib.h"\r
-\r
-//\r
-// Handle for the Deferred Image Load Protocol instance produced by this driver.\r
-//\r
-EFI_HANDLE mDeferredImageHandle = NULL;\r
-BOOLEAN mIsProtocolInstalled = FALSE;\r
-EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;\r
-DEFERRED_IMAGE_TABLE mDeferredImage = {\r
- 0, // Deferred image count\r
- NULL // The deferred image info\r
-};\r
-\r
-EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad = {\r
- GetDefferedImageInfo\r
-};\r
-\r
-/**\r
- Get the image type.\r
-\r
- @param[in] File This is a pointer to the device path of the file\r
- that is being dispatched.\r
-\r
- @return UINT32 Image Type\r
-\r
-**/\r
-UINT32\r
-GetFileType (\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_HANDLE DeviceHandle;\r
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
-\r
- //\r
- // First check to see if File is from a Firmware Volume\r
- //\r
- DeviceHandle = NULL;\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
- Status = gBS->LocateDevicePath (\r
- &gEfiFirmwareVolume2ProtocolGuid,\r
- &TempDevicePath,\r
- &DeviceHandle\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Status = gBS->OpenProtocol (\r
- DeviceHandle,\r
- &gEfiFirmwareVolume2ProtocolGuid,\r
- NULL,\r
- NULL,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- return IMAGE_FROM_FV;\r
- }\r
- }\r
-\r
- //\r
- // Next check to see if File is from a Block I/O device\r
- //\r
- DeviceHandle = NULL;\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
- Status = gBS->LocateDevicePath (\r
- &gEfiBlockIoProtocolGuid,\r
- &TempDevicePath,\r
- &DeviceHandle\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- BlockIo = NULL;\r
- Status = gBS->OpenProtocol (\r
- DeviceHandle,\r
- &gEfiBlockIoProtocolGuid,\r
- (VOID **) &BlockIo,\r
- NULL,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (!EFI_ERROR (Status) && BlockIo != NULL) {\r
- if (BlockIo->Media != NULL) {\r
- if (BlockIo->Media->RemovableMedia) {\r
- //\r
- // Block I/O is present and specifies the media is removable\r
- //\r
- return IMAGE_FROM_REMOVABLE_MEDIA;\r
- } else {\r
- //\r
- // Block I/O is present and specifies the media is not removable\r
- //\r
- return IMAGE_FROM_FIXED_MEDIA;\r
- }\r
- }\r
- }\r
- }\r
-\r
- //\r
- // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
- // the device path supports the Simple File System Protocol.\r
- //\r
- DeviceHandle = NULL;\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
- Status = gBS->LocateDevicePath (\r
- &gEfiSimpleFileSystemProtocolGuid,\r
- &TempDevicePath,\r
- &DeviceHandle\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Simple File System is present without Block I/O, so assume media is fixed.\r
- //\r
- return IMAGE_FROM_FIXED_MEDIA;\r
- }\r
-\r
- //\r
- // File is not from an FV, Block I/O or Simple File System, so the only options\r
- // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
- //\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
- while (!IsDevicePathEndType (TempDevicePath)) {\r
- switch (DevicePathType (TempDevicePath)) {\r
-\r
- case MEDIA_DEVICE_PATH:\r
- if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
- return IMAGE_FROM_OPTION_ROM;\r
- }\r
- break;\r
-\r
- case MESSAGING_DEVICE_PATH:\r
- if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
- return IMAGE_FROM_REMOVABLE_MEDIA;\r
- }\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
- TempDevicePath = NextDevicePathNode (TempDevicePath);\r
- }\r
- return IMAGE_UNKNOWN;\r
-}\r
-\r
-\r
-/**\r
- Get current user's access right.\r
-\r
- @param[out] AccessControl Points to the user's access control data, the\r
- caller should free data buffer.\r
- @param[in] AccessType The type of user access control.\r
-\r
- @retval EFI_SUCCESS Get current user access control successfully\r
- @retval others Fail to get current user access control\r
-\r
-**/\r
-EFI_STATUS\r
-GetAccessControl (\r
- OUT EFI_USER_INFO_ACCESS_CONTROL **AccessControl,\r
- IN UINT32 AccessType\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_USER_INFO_HANDLE UserInfo;\r
- EFI_USER_INFO *Info;\r
- UINTN InfoSize;\r
- EFI_USER_INFO_ACCESS_CONTROL *Access;\r
- EFI_USER_PROFILE_HANDLE CurrentUser;\r
- UINTN CheckLen;\r
- EFI_USER_MANAGER_PROTOCOL *UserManager;\r
-\r
- CurrentUser = NULL;\r
- Status = gBS->LocateProtocol (\r
- &gEfiUserManagerProtocolGuid,\r
- NULL,\r
- (VOID **) &UserManager\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // Get current user access information.\r
- //\r
- UserManager->Current (UserManager, &CurrentUser);\r
-\r
- UserInfo = NULL;\r
- Info = NULL;\r
- InfoSize = 0;\r
- while (TRUE) {\r
- //\r
- // Get next user information.\r
- //\r
- Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = UserManager->GetInfo (\r
- UserManager,\r
- CurrentUser,\r
- UserInfo,\r
- Info,\r
- &InfoSize\r
- );\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- if (Info != NULL) {\r
- FreePool (Info);\r
- }\r
- Info = AllocateZeroPool (InfoSize);\r
- ASSERT (Info != NULL);\r
- Status = UserManager->GetInfo (\r
- UserManager,\r
- CurrentUser,\r
- UserInfo,\r
- Info,\r
- &InfoSize\r
- );\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
-\r
- ASSERT (Info != NULL);\r
- if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {\r
- continue;\r
- }\r
-\r
- //\r
- // Get specified access information.\r
- //\r
- CheckLen = 0;\r
- while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r
- Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen);\r
- if (Access->Type == AccessType) {\r
- *AccessControl = AllocateZeroPool (Access->Size);\r
- ASSERT (*AccessControl != NULL);\r
- CopyMem (*AccessControl, Access, Access->Size);\r
- FreePool (Info);\r
- return EFI_SUCCESS;\r
- }\r
- CheckLen += Access->Size;\r
- }\r
- }\r
-\r
- if (Info != NULL) {\r
- FreePool (Info);\r
- }\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Get file name from device path.\r
-\r
- The file name may contain one or more device path node. Save the file name in a\r
- buffer if file name is found. The caller is responsible to free the buffer.\r
-\r
- @param[in] DevicePath A pointer to a device path.\r
- @param[out] FileName The callee allocated buffer to save the file name if file name is found.\r
- @param[out] FileNameOffset The offset of file name in device path if file name is found.\r
-\r
- @retval UINTN The file name length. 0 means file name is not found.\r
-\r
-**/\r
-UINTN\r
-GetFileName (\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- OUT UINT8 **FileName,\r
- OUT UINTN *FileNameOffset\r
- )\r
-{\r
- UINTN Length;\r
- EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
- EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r
- CHAR8 *NodeStr;\r
- UINTN NodeStrLength;\r
- CHAR16 LastNodeChar;\r
- CHAR16 FirstNodeChar;\r
-\r
- //\r
- // Get the length of DevicePath before file name.\r
- //\r
- Length = 0;\r
- RootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
- while (!IsDevicePathEnd (RootDevicePath)) {\r
- if ((DevicePathType(RootDevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType(RootDevicePath) == MEDIA_FILEPATH_DP)) {\r
- break;\r
- }\r
- Length += DevicePathNodeLength (RootDevicePath);\r
- RootDevicePath = NextDevicePathNode (RootDevicePath);\r
- }\r
-\r
- *FileNameOffset = Length;\r
- if (Length == 0) {\r
- return 0;\r
- }\r
-\r
- //\r
- // Get the file name length.\r
- //\r
- Length = 0;\r
- TmpDevicePath = RootDevicePath;\r
- while (!IsDevicePathEnd (TmpDevicePath)) {\r
- if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r
- break;\r
- }\r
- Length += DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
- }\r
- if (Length == 0) {\r
- return 0;\r
- }\r
-\r
- *FileName = AllocateZeroPool (Length);\r
- ASSERT (*FileName != NULL);\r
-\r
- //\r
- // Copy the file name to the buffer.\r
- //\r
- Length = 0;\r
- LastNodeChar = '\\';\r
- TmpDevicePath = RootDevicePath;\r
- while (!IsDevicePathEnd (TmpDevicePath)) {\r
- if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r
- break;\r
- }\r
-\r
- FirstNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *)((UINT8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r
- NodeStr = (CHAR8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
- NodeStrLength = DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL) - sizeof(CHAR16);\r
-\r
- if ((FirstNodeChar == '\\') && (LastNodeChar == '\\')) {\r
- //\r
- // Skip separator "\" when there are two separators.\r
- //\r
- NodeStr += sizeof (CHAR16);\r
- NodeStrLength -= sizeof (CHAR16);\r
- } else if ((FirstNodeChar != '\\') && (LastNodeChar != '\\')) {\r
- //\r
- // Add separator "\" when there is no separator.\r
- //\r
- WriteUnaligned16 ((UINT16 *)(*FileName + Length), '\\');\r
- Length += sizeof (CHAR16);\r
- }\r
- CopyMem (*FileName + Length, NodeStr, NodeStrLength);\r
- Length += NodeStrLength;\r
-\r
- LastNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *) (NodeStr + NodeStrLength - sizeof(CHAR16)));\r
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
- }\r
-\r
- return Length;\r
-}\r
-\r
-\r
-/**\r
- Check whether the DevicePath2 is identical with DevicePath1, or identical with\r
- DevicePath1's child device path.\r
-\r
- If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device\r
- path, then TRUE returned. Otherwise, FALSE is returned.\r
-\r
- If DevicePath1 is NULL, then ASSERT().\r
- If DevicePath2 is NULL, then ASSERT().\r
-\r
- @param[in] DevicePath1 A pointer to a device path.\r
- @param[in] DevicePath2 A pointer to a device path.\r
-\r
- @retval TRUE Two device paths are identical , or DevicePath2 is\r
- DevicePath1's child device path.\r
- @retval FALSE Two device paths are not identical, and DevicePath2\r
- is not DevicePath1's child device path.\r
-\r
-**/\r
-BOOLEAN\r
-CheckDevicePath (\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2\r
- )\r
-{\r
- UINTN DevicePathSize;\r
- UINTN FileNameSize1;\r
- UINTN FileNameSize2;\r
- UINT8 *FileName1;\r
- UINT8 *FileName2;\r
- UINTN FileNameOffset1;\r
- UINTN FileNameOffset2;\r
- BOOLEAN DevicePathEqual;\r
-\r
- FileName1 = NULL;\r
- FileName2 = NULL;\r
- DevicePathEqual = TRUE;\r
-\r
- ASSERT (DevicePath1 != NULL);\r
- ASSERT (DevicePath2 != NULL);\r
- if (IsDevicePathEnd (DevicePath1)) {\r
- return FALSE;\r
- }\r
-\r
- //\r
- // The file name may contain one or more device path node.\r
- // To compare the file name, copy file name to a buffer and compare the buffer.\r
- //\r
- FileNameSize1 = GetFileName (DevicePath1, &FileName1, &FileNameOffset1);\r
- if (FileNameSize1 != 0) {\r
- FileNameSize2 = GetFileName (DevicePath2, &FileName2, &FileNameOffset2);\r
- if (FileNameOffset1 != FileNameOffset2) {\r
- DevicePathEqual = FALSE;\r
- goto Done;\r
- }\r
- if (CompareMem (DevicePath1, DevicePath2, FileNameOffset1) != 0) {\r
- DevicePathEqual = FALSE;\r
- goto Done;\r
- }\r
- if (FileNameSize1 > FileNameSize2) {\r
- DevicePathEqual = FALSE;\r
- goto Done;\r
- }\r
- if (CompareMem (FileName1, FileName2, FileNameSize1) != 0) {\r
- DevicePathEqual = FALSE;\r
- goto Done;\r
- }\r
- DevicePathEqual = TRUE;\r
- goto Done;\r
- }\r
-\r
- DevicePathSize = GetDevicePathSize (DevicePath1);\r
- if (DevicePathSize > GetDevicePathSize (DevicePath2)) {\r
- return FALSE;\r
- }\r
-\r
- //\r
- // Exclude the end of device path node.\r
- //\r
- DevicePathSize -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
- if (CompareMem (DevicePath1, DevicePath2, DevicePathSize) != 0) {\r
- DevicePathEqual = FALSE;\r
- }\r
-\r
-Done:\r
- if (FileName1 != NULL) {\r
- FreePool (FileName1);\r
- }\r
- if (FileName2 != NULL) {\r
- FreePool (FileName2);\r
- }\r
- return DevicePathEqual;\r
-}\r
-\r
-\r
-/**\r
- Check whether the image pointed to by DevicePath is in the device path list\r
- specified by AccessType.\r
-\r
- @param[in] DevicePath Points to device path.\r
- @param[in] AccessType The type of user access control.\r
-\r
- @retval TRUE The DevicePath is in the specified List.\r
- @retval FALSE The DevicePath is not in the specified List.\r
-\r
-**/\r
-BOOLEAN\r
-IsDevicePathInList (\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- IN UINT32 AccessType\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_USER_INFO_ACCESS_CONTROL *Access;\r
- EFI_DEVICE_PATH_PROTOCOL *Path;\r
- UINTN OffSet;\r
-\r
- Status = GetAccessControl (&Access, AccessType);\r
- if (EFI_ERROR (Status)) {\r
- return FALSE;\r
- }\r
-\r
- OffSet = 0;\r
- while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r
- Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet);\r
- if (CheckDevicePath (Path, DevicePath)) {\r
- //\r
- // The device path is found in list.\r
- //\r
- FreePool (Access);\r
- return TRUE;\r
- }\r
- OffSet += GetDevicePathSize (Path);\r
- }\r
-\r
- FreePool (Access);\r
- return FALSE;\r
-}\r
-\r
-\r
-/**\r
- Check whether the image pointed to by DevicePath is permitted to load.\r
-\r
- @param[in] DevicePath Points to device path\r
-\r
- @retval TRUE The image pointed by DevicePath is permitted to load.\r
- @retval FALSE The image pointed by DevicePath is forbidden to load.\r
-\r
-**/\r
-BOOLEAN\r
-VerifyDevicePath (\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
- )\r
-{\r
- if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {\r
- //\r
- // This access control overrides any restrictions put in place by the\r
- // EFI_USER_INFO_ACCESS_FORBID_LOAD record.\r
- //\r
- return TRUE;\r
- }\r
-\r
- if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {\r
- //\r
- // The device path is found in the forbidden list.\r
- //\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-\r
-/**\r
- Check the image pointed by DevicePath is a boot option or not.\r
-\r
- @param[in] DevicePath Points to device path.\r
-\r
- @retval TRUE The image pointed by DevicePath is a boot option.\r
- @retval FALSE The image pointed by DevicePath is not a boot option.\r
-\r
-**/\r
-BOOLEAN\r
-IsBootOption (\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT16 *BootOrderList;\r
- UINTN BootOrderListSize;\r
- UINTN Index;\r
- CHAR16 StrTemp[20];\r
- UINT8 *OptionBuffer;\r
- UINT8 *OptionPtr;\r
- EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
-\r
- //\r
- // Get BootOrder\r
- //\r
- BootOrderListSize = 0;\r
- BootOrderList = NULL;\r
- Status = gRT->GetVariable (\r
- L"BootOrder",\r
- &gEfiGlobalVariableGuid,\r
- NULL,\r
- &BootOrderListSize,\r
- NULL\r
- );\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- BootOrderList = AllocateZeroPool (BootOrderListSize);\r
- ASSERT (BootOrderList != NULL);\r
- Status = gRT->GetVariable (\r
- L"BootOrder",\r
- &gEfiGlobalVariableGuid,\r
- NULL,\r
- &BootOrderListSize,\r
- BootOrderList\r
- );\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // No Boot option\r
- //\r
- return FALSE;\r
- }\r
-\r
- OptionBuffer = NULL;\r
- for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
- //\r
- // Try to find the DevicePath in BootOption\r
- //\r
- UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r
- GetEfiGlobalVariable2 (StrTemp, (VOID**)&OptionBuffer, NULL);\r
- if (OptionBuffer == NULL) {\r
- continue;\r
- }\r
-\r
- //\r
- // Check whether the image is forbidden.\r
- //\r
-\r
- OptionPtr = OptionBuffer;\r
- //\r
- // Skip attribute.\r
- //\r
- OptionPtr += sizeof (UINT32);\r
-\r
- //\r
- // Skip device path length.\r
- //\r
- OptionPtr += sizeof (UINT16);\r
-\r
- //\r
- // Skip descript string\r
- //\r
- OptionPtr += StrSize ((UINT16 *) OptionPtr);\r
-\r
- //\r
- // Now OptionPtr points to Device Path.\r
- //\r
- OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;\r
-\r
- if (CheckDevicePath (DevicePath, OptionDevicePath)) {\r
- FreePool (OptionBuffer);\r
- OptionBuffer = NULL;\r
- return TRUE;\r
- }\r
- FreePool (OptionBuffer);\r
- OptionBuffer = NULL;\r
- }\r
-\r
- if (BootOrderList != NULL) {\r
- FreePool (BootOrderList);\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-\r
-/**\r
- Add the image info to a deferred image list.\r
-\r
- @param[in] ImageDevicePath A pointer to the device path of a image.\r
- @param[in] Image Points to the first byte of the image, or NULL if the\r
- image is not available.\r
- @param[in] ImageSize The size of the image, or 0 if the image is not available.\r
-\r
-**/\r
-VOID\r
-PutDefferedImageInfo (\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
- IN VOID *Image,\r
- IN UINTN ImageSize\r
- )\r
-{\r
- DEFERRED_IMAGE_INFO *CurImageInfo;\r
- UINTN PathSize;\r
-\r
- //\r
- // Expand memory for the new deferred image.\r
- //\r
- if (mDeferredImage.Count == 0) {\r
- mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));\r
- ASSERT (mDeferredImage.ImageInfo != NULL);\r
- } else {\r
- CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));\r
- ASSERT (CurImageInfo != NULL);\r
-\r
- CopyMem (\r
- CurImageInfo,\r
- mDeferredImage.ImageInfo,\r
- mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)\r
- );\r
- FreePool (mDeferredImage.ImageInfo);\r
- mDeferredImage.ImageInfo = CurImageInfo;\r
- }\r
- mDeferredImage.Count++;\r
-\r
- //\r
- // Save the deferred image information.\r
- //\r
- CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];\r
- PathSize = GetDevicePathSize (ImageDevicePath);\r
- CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);\r
- ASSERT (CurImageInfo->ImageDevicePath != NULL);\r
- CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);\r
-\r
- CurImageInfo->Image = Image;\r
- CurImageInfo->ImageSize = ImageSize;\r
- CurImageInfo->BootOption = IsBootOption (ImageDevicePath);\r
-}\r
-\r
-\r
-/**\r
- Returns information about a deferred image.\r
-\r
- This function returns information about a single deferred image. The deferred images are\r
- numbered consecutively, starting with 0. If there is no image which corresponds to\r
- ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by\r
- iteratively calling this function until EFI_NOT_FOUND is returned.\r
- Image may be NULL and ImageSize set to 0 if the decision to defer execution was made\r
- because of the location of the executable image, rather than its actual contents.\r
-\r
- @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r
- @param[in] ImageIndex Zero-based index of the deferred index.\r
- @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.\r
- The device path should not be freed by the caller.\r
- @param[out] Image On return, points to the first byte of the image or NULL if the\r
- image is not available. The image should not be freed by the caller\r
- unless LoadImage() has been successfully called.\r
- @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.\r
- @param[out] BootOption On return, points to TRUE if the image was intended as a boot option\r
- or FALSE if it was not intended as a boot option.\r
-\r
- @retval EFI_SUCCESS Image information returned successfully.\r
- @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.\r
- @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or\r
- BootOption is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-GetDefferedImageInfo (\r
- IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,\r
- IN UINTN ImageIndex,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,\r
- OUT VOID **Image,\r
- OUT UINTN *ImageSize,\r
- OUT BOOLEAN *BootOption\r
- )\r
-{\r
- DEFERRED_IMAGE_INFO *ReqImageInfo;\r
-\r
- //\r
- // Check the parameter.\r
- //\r
-\r
- if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((ImageDevicePath == NULL) || (BootOption == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (ImageIndex >= mDeferredImage.Count) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // Get the request deferred image.\r
- //\r
- ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];\r
-\r
- *ImageDevicePath = ReqImageInfo->ImageDevicePath;\r
- *Image = ReqImageInfo->Image;\r
- *ImageSize = ReqImageInfo->ImageSize;\r
- *BootOption = ReqImageInfo->BootOption;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Provides the service of deferring image load based on platform policy control,\r
- and installs Deferred Image Load Protocol.\r
-\r
- @param[in] AuthenticationStatus This is the authentication status returned from the\r
- security measurement services for the input file.\r
- @param[in] File This is a pointer to the device path of the file that\r
- is being dispatched. This will optionally be used for\r
- logging.\r
- @param[in] FileBuffer File buffer matches the input file device path.\r
- @param[in] FileSize Size of File buffer matches the input file device path.\r
- @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
-\r
- @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start\r
- UEFI device drivers on the device path specified by DevicePath.\r
- @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
- FileBuffer did authenticate, and the platform policy dictates\r
- that the DXE Foundation may use the file.\r
- @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no\r
- permission to start UEFI device drivers on the device path specified\r
- by DevicePath.\r
- @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load\r
- drivers from the device path specified by DevicePath. The\r
- image has been added into the list of the deferred images.\r
- @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
- authenticate, and the platform policy dictates that the DXE\r
- Foundation many not use File.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DxeDeferImageLoadHandler (\r
- IN UINT32 AuthenticationStatus,\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
- IN VOID *FileBuffer,\r
- IN UINTN FileSize,\r
- IN BOOLEAN BootPolicy\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_USER_PROFILE_HANDLE CurrentUser;\r
- UINT32 Policy;\r
- UINT32 FileType;\r
-\r
- //\r
- // Ignore if File is NULL.\r
- //\r
- if (File == NULL) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // Check whether user has a logon.\r
- //\r
- CurrentUser = NULL;\r
- if (mUserManager != NULL) {\r
- mUserManager->Current (mUserManager, &CurrentUser);\r
- if (CurrentUser != NULL) {\r
- //\r
- // The user is logon; verify the FilePath by current user access policy.\r
- //\r
- if (!VerifyDevicePath (File)) {\r
- DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- //\r
- // Still no user logon.\r
- // Check the file type and get policy setting.\r
- //\r
- FileType = GetFileType (File);\r
- Policy = PcdGet32 (PcdDeferImageLoadPolicy);\r
- if ((Policy & FileType) == FileType) {\r
- //\r
- // This file type is secure to load.\r
- //\r
- return EFI_SUCCESS;\r
- }\r
-\r
- DEBUG ((EFI_D_INFO, "[Security] No user identified, the image is deferred to load!\n"));\r
- PutDefferedImageInfo (File, FileBuffer, FileSize);\r
-\r
- //\r
- // Install the Deferred Image Load Protocol onto a new handle.\r
- //\r
- if (!mIsProtocolInstalled) {\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &mDeferredImageHandle,\r
- &gEfiDeferredImageLoadProtocolGuid,\r
- &gDeferredImageLoad,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- mIsProtocolInstalled = TRUE;\r
- }\r
-\r
- return EFI_ACCESS_DENIED;\r
-}\r
-\r
-/**\r
- Locate user manager protocol when user manager is installed.\r
-\r
- @param[in] Event The Event that is being processed, not used.\r
- @param[in] Context Event Context, not used.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-FindUserManagerProtocol (\r
- IN EFI_EVENT Event,\r
- IN VOID* Context\r
- )\r
-{\r
- gBS->LocateProtocol (\r
- &gEfiUserManagerProtocolGuid,\r
- NULL,\r
- (VOID **) &mUserManager\r
- );\r
-\r
-}\r
-\r
-\r
-/**\r
- Register security handler for deferred image load.\r
-\r
- @param[in] ImageHandle ImageHandle of the loaded driver.\r
- @param[in] SystemTable Pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The handlers were registered successfully.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DxeDeferImageLoadLibConstructor (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- VOID *Registration;\r
-\r
- //\r
- // Register user manager notification function.\r
- //\r
- EfiCreateProtocolNotifyEvent (\r
- &gEfiUserManagerProtocolGuid,\r
- TPL_CALLBACK,\r
- FindUserManagerProtocol,\r
- NULL,\r
- &Registration\r
- );\r
-\r
- return RegisterSecurity2Handler (\r
- DxeDeferImageLoadHandler,\r
- EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD\r
- );\r
-}\r
-\r
-\r