]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
Add security package to repository.
[mirror_edk2.git] / SecurityPkg / Library / DxeDeferImageLoadLib / DxeDeferImageLoadLib.c
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
new file mode 100644 (file)
index 0000000..f7fe594
--- /dev/null
@@ -0,0 +1,858 @@
+/** @file\r
+  Implement defer image load services for user identification in UEFI2.2.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\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
+/**\r
+  Convert the '/' to '\' in the specified string.\r
+\r
+  @param[in, out]  Str       Points to the string to convert.\r
+\r
+**/\r
+VOID\r
+ConvertDPStr (\r
+  IN OUT EFI_STRING                     Str \r
+  )\r
+{\r
+  INTN                                  Count;\r
+  INTN                                  Index;\r
+  \r
+  Count = StrSize(Str) / 2 - 1;\r
+\r
+  if (Count < 4) {\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Convert device path string.\r
+  //\r
+  Index = Count - 1;\r
+  while (Index > 0) {\r
+    //\r
+    // Find the last '/'.\r
+    //\r
+    for (Index = Count - 1; Index > 0; Index--) {\r
+      if (Str[Index] == L'/')\r
+        break;\r
+    }\r
+\r
+    //\r
+    // Check next char.\r
+    //\r
+    if (Str[Index + 1] == L'\\')\r
+      return;\r
+    \r
+    Str[Index] = L'\\';\r
+    \r
+    //\r
+    // Check previous char.\r
+    //\r
+    if ((Index > 0) && (Str[Index - 1] == L'\\')) {\r
+      CopyMem (&Str[Index - 1], &Str[Index], (UINTN) ((Count - Index + 1) * sizeof (CHAR16)));\r
+      return;\r
+    }\r
+    Index--;\r
+  }\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
+  EFI_STATUS                            Status;\r
+  EFI_STRING                            DevicePathStr1;\r
+  EFI_STRING                            DevicePathStr2;\r
+  UINTN                                 StrLen1;\r
+  UINTN                                 StrLen2;\r
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL      *DevicePathText;\r
+  BOOLEAN                               DevicePathEqual;\r
+\r
+  ASSERT (DevicePath1 != NULL);\r
+  ASSERT (DevicePath2 != NULL);\r
+  \r
+  DevicePathEqual = FALSE;\r
+  DevicePathText  = NULL;\r
+  Status = gBS->LocateProtocol ( \r
+                  &gEfiDevicePathToTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &DevicePathText\r
+                  );\r
+  ASSERT (Status == EFI_SUCCESS);\r
+  \r
+  //\r
+  // Get first device path string.\r
+  //\r
+  DevicePathStr1 = DevicePathText->ConvertDevicePathToText (DevicePath1, TRUE, TRUE);\r
+  ConvertDPStr (DevicePathStr1);\r
+  //\r
+  // Get second device path string.\r
+  //\r
+  DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE);\r
+  ConvertDPStr (DevicePathStr2);\r
+  \r
+  //\r
+  // Compare device path string.\r
+  //\r
+  StrLen1 = StrSize (DevicePathStr1);\r
+  StrLen2 = StrSize (DevicePathStr2);\r
+  if (StrLen1 > StrLen2) {\r
+    DevicePathEqual = FALSE;\r
+    goto Done;\r
+  }\r
+  \r
+  if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) {\r
+    DevicePathEqual = TRUE;\r
+  }\r
+\r
+Done:\r
+  FreePool (DevicePathStr1);\r
+  FreePool (DevicePathStr2);\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    TURE        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    TURE        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    TURE        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
+    OptionBuffer = GetEfiGlobalVariable (StrTemp);\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
+\r
+  @retval EFI_SUCCESS               The file specified by File did authenticate, and the\r
+                                    platform policy dictates that the DXE Core may use File.\r
+  @retval EFI_INVALID_PARAMETER     File is NULL.\r
+  @retval EFI_SECURITY_VIOLATION    The file specified by File did not authenticate, and\r
+                                    the platform policy dictates that File should be placed\r
+                                    in the untrusted state. A file may be promoted from\r
+                                    the untrusted to the trusted state at a future time\r
+                                    with a call to the Trust() DXE Service.\r
+  @retval EFI_ACCESS_DENIED         The file specified by File did not authenticate, and\r
+                                    the platform policy dictates that File should not be\r
+                                    used for any purpose.\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
+  )\r
+\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_USER_PROFILE_HANDLE              CurrentUser;\r
+  UINT32                               Policy;\r
+  UINT32                               FileType;\r
+\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\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_ACCESS_DENIED;\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_ERROR, "[Security] No user identified, the image is deferred to load!\n"));\r
+  PutDefferedImageInfo (File, NULL, 0);\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 RegisterSecurityHandler (\r
+           DxeDeferImageLoadHandler,\r
+           EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \r
+           );      \r
+}\r
+\r
+\r