Signed-off-by: Dong Guo <guo.dong@intel.com> Reviewed-by: Ni, Ruiyu <ruiyu.ni@intel.com> Reviewed-by: Ouyang, Qian <qian.ouyang@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14905 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			934 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			934 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implement defer image load services for user identification in UEFI2.2.
 | 
						|
 | 
						|
Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials 
 | 
						|
are licensed and made available under the terms and conditions of the BSD License 
 | 
						|
which accompanies this distribution.  The full text of the license may be found at 
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "DxeDeferImageLoadLib.h"
 | 
						|
 | 
						|
//
 | 
						|
// Handle for the Deferred Image Load Protocol instance produced by this driver.
 | 
						|
//
 | 
						|
EFI_HANDLE                       mDeferredImageHandle = NULL;
 | 
						|
BOOLEAN                          mIsProtocolInstalled = FALSE;
 | 
						|
EFI_USER_MANAGER_PROTOCOL        *mUserManager        = NULL;
 | 
						|
DEFERRED_IMAGE_TABLE             mDeferredImage       = {
 | 
						|
  0,       // Deferred image count
 | 
						|
  NULL     // The deferred image info
 | 
						|
};
 | 
						|
 | 
						|
EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad   = {
 | 
						|
  GetDefferedImageInfo
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Get the image type.
 | 
						|
 | 
						|
  @param[in]    File    This is a pointer to the device path of the file
 | 
						|
                        that is being dispatched. 
 | 
						|
 | 
						|
  @return       UINT32  Image Type             
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
GetFileType (
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  EFI_HANDLE                        DeviceHandle; 
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL          *TempDevicePath;
 | 
						|
  EFI_BLOCK_IO_PROTOCOL             *BlockIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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 IMAGE_FROM_FV;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Next check to see if File is from a Block I/O device
 | 
						|
  //
 | 
						|
  DeviceHandle   = NULL;
 | 
						|
  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
 | 
						|
  Status = gBS->LocateDevicePath (
 | 
						|
                  &gEfiBlockIoProtocolGuid,
 | 
						|
                  &TempDevicePath,
 | 
						|
                  &DeviceHandle
 | 
						|
                  );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    BlockIo = NULL;
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    DeviceHandle,
 | 
						|
                    &gEfiBlockIoProtocolGuid,
 | 
						|
                    (VOID **) &BlockIo,
 | 
						|
                    NULL,
 | 
						|
                    NULL,
 | 
						|
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status) && BlockIo != NULL) {
 | 
						|
      if (BlockIo->Media != NULL) {
 | 
						|
        if (BlockIo->Media->RemovableMedia) {
 | 
						|
          //
 | 
						|
          // Block I/O is present and specifies the media is removable
 | 
						|
          //
 | 
						|
          return IMAGE_FROM_REMOVABLE_MEDIA;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Block I/O is present and specifies the media is not removable
 | 
						|
          //
 | 
						|
          return IMAGE_FROM_FIXED_MEDIA;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // File is not in a Firmware Volume or on a Block I/O device, so check to see if 
 | 
						|
  // the device path supports the Simple File System Protocol.
 | 
						|
  //
 | 
						|
  DeviceHandle   = NULL;
 | 
						|
  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
 | 
						|
  Status = gBS->LocateDevicePath (
 | 
						|
                  &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
                  &TempDevicePath,
 | 
						|
                  &DeviceHandle
 | 
						|
                  );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Simple File System is present without Block I/O, so assume media is fixed.
 | 
						|
    //
 | 
						|
    return IMAGE_FROM_FIXED_MEDIA;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // File is not from an FV, Block I/O or Simple File System, so the only options
 | 
						|
  // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.  
 | 
						|
  //
 | 
						|
  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
 | 
						|
  while (!IsDevicePathEndType (TempDevicePath)) {
 | 
						|
    switch (DevicePathType (TempDevicePath)) {
 | 
						|
    
 | 
						|
    case MEDIA_DEVICE_PATH:
 | 
						|
      if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {
 | 
						|
        return IMAGE_FROM_OPTION_ROM;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case MESSAGING_DEVICE_PATH:
 | 
						|
      if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
 | 
						|
        return IMAGE_FROM_REMOVABLE_MEDIA;
 | 
						|
      } 
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    TempDevicePath = NextDevicePathNode (TempDevicePath);
 | 
						|
  }
 | 
						|
  return IMAGE_UNKNOWN; 
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get current user's access right.
 | 
						|
 | 
						|
  @param[out]  AccessControl Points to the user's access control data, the
 | 
						|
                             caller should free data buffer.
 | 
						|
  @param[in]   AccessType    The type of user access control.
 | 
						|
 | 
						|
  @retval      EFI_SUCCESS   Get current user access control successfully
 | 
						|
  @retval      others        Fail to get current user access control
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetAccessControl (
 | 
						|
  OUT  EFI_USER_INFO_ACCESS_CONTROL     **AccessControl,
 | 
						|
  IN   UINT32                           AccessType
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_USER_INFO_HANDLE          UserInfo;
 | 
						|
  EFI_USER_INFO                 *Info;
 | 
						|
  UINTN                         InfoSize;
 | 
						|
  EFI_USER_INFO_ACCESS_CONTROL  *Access;
 | 
						|
  EFI_USER_PROFILE_HANDLE       CurrentUser;
 | 
						|
  UINTN                         CheckLen;
 | 
						|
  EFI_USER_MANAGER_PROTOCOL     *UserManager;
 | 
						|
 | 
						|
  CurrentUser = NULL;
 | 
						|
  Status = gBS->LocateProtocol (
 | 
						|
                  &gEfiUserManagerProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  (VOID **) &UserManager
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Get current user access information.
 | 
						|
  //
 | 
						|
  UserManager->Current (UserManager, &CurrentUser);
 | 
						|
 | 
						|
  UserInfo = NULL;
 | 
						|
  Info     = NULL;
 | 
						|
  InfoSize = 0;
 | 
						|
  while (TRUE) {
 | 
						|
    //
 | 
						|
    // Get next user information.
 | 
						|
    //
 | 
						|
    Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = UserManager->GetInfo (
 | 
						|
                            UserManager,
 | 
						|
                            CurrentUser,
 | 
						|
                            UserInfo,
 | 
						|
                            Info,
 | 
						|
                            &InfoSize
 | 
						|
                            );
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      if (Info != NULL) {
 | 
						|
        FreePool (Info);
 | 
						|
      }
 | 
						|
      Info = AllocateZeroPool (InfoSize);
 | 
						|
      ASSERT (Info != NULL);
 | 
						|
      Status = UserManager->GetInfo (
 | 
						|
                              UserManager,
 | 
						|
                              CurrentUser,
 | 
						|
                              UserInfo,
 | 
						|
                              Info,
 | 
						|
                              &InfoSize
 | 
						|
                              );
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    
 | 
						|
    ASSERT (Info != NULL);
 | 
						|
    if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Get specified access information.
 | 
						|
    //
 | 
						|
    CheckLen  = 0;
 | 
						|
    while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
 | 
						|
      Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen);
 | 
						|
      if ((Access->Type == AccessType)) {
 | 
						|
        *AccessControl = AllocateZeroPool (Access->Size);
 | 
						|
        ASSERT (*AccessControl != NULL);
 | 
						|
        CopyMem (*AccessControl, Access, Access->Size);
 | 
						|
        FreePool (Info);
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
      CheckLen += Access->Size;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (Info != NULL) {
 | 
						|
    FreePool (Info);
 | 
						|
  }
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get file name from device path.
 | 
						|
 | 
						|
  The file name may contain one or more device path node. Save the file name in a 
 | 
						|
  buffer if file name is found. The caller is responsible to free the buffer.  
 | 
						|
  
 | 
						|
  @param[in]  DevicePath     A pointer to a device path.
 | 
						|
  @param[out] FileName       The callee allocated buffer to save the file name if file name is found.
 | 
						|
  @param[out] FileNameOffset The offset of file name in device path if file name is found.
 | 
						|
  
 | 
						|
  @retval     UINTN          The file name length. 0 means file name is not found.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN 
 | 
						|
GetFileName (
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL          *DevicePath,
 | 
						|
  OUT UINT8                                   **FileName,
 | 
						|
  OUT UINTN                                   *FileNameOffset
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                                       Length;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL                    *TmpDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL                    *RootDevicePath;
 | 
						|
  CHAR8                                       *NodeStr;
 | 
						|
  UINTN                                       NodeStrLength;
 | 
						|
  CHAR16                                      LastNodeChar;
 | 
						|
  CHAR16                                      FirstNodeChar;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the length of DevicePath before file name.
 | 
						|
  //
 | 
						|
  Length = 0;
 | 
						|
  RootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
 | 
						|
  while (!IsDevicePathEnd (RootDevicePath)) {
 | 
						|
    if ((DevicePathType(RootDevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType(RootDevicePath) == MEDIA_FILEPATH_DP)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    Length += DevicePathNodeLength (RootDevicePath);
 | 
						|
    RootDevicePath = NextDevicePathNode (RootDevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  *FileNameOffset = Length;
 | 
						|
  if (Length == 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the file name length.
 | 
						|
  //
 | 
						|
  Length = 0;
 | 
						|
  TmpDevicePath = RootDevicePath;
 | 
						|
  while (!IsDevicePathEnd (TmpDevicePath)) {
 | 
						|
    if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    Length += DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
 | 
						|
    TmpDevicePath = NextDevicePathNode (TmpDevicePath);
 | 
						|
  }
 | 
						|
  if (Length == 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  *FileName = AllocateZeroPool (Length);
 | 
						|
  ASSERT (*FileName != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the file name to the buffer.
 | 
						|
  //
 | 
						|
  Length = 0;
 | 
						|
  LastNodeChar = '\\';
 | 
						|
  TmpDevicePath = RootDevicePath;
 | 
						|
  while (!IsDevicePathEnd (TmpDevicePath)) {
 | 
						|
    if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    FirstNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *)((UINT8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL)));
 | 
						|
    NodeStr = (CHAR8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL);
 | 
						|
    NodeStrLength = DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL) - sizeof(CHAR16);
 | 
						|
    
 | 
						|
    if ((FirstNodeChar == '\\') && (LastNodeChar == '\\')) {
 | 
						|
      //
 | 
						|
      // Skip separator "\" when there are two separators.
 | 
						|
      //
 | 
						|
      NodeStr += sizeof (CHAR16);
 | 
						|
      NodeStrLength -= sizeof (CHAR16);      
 | 
						|
    } else if ((FirstNodeChar != '\\') && (LastNodeChar != '\\')) {
 | 
						|
      //
 | 
						|
      // Add separator "\" when there is no separator.
 | 
						|
      //
 | 
						|
      WriteUnaligned16 ((UINT16 *)(*FileName + Length), '\\');
 | 
						|
      Length += sizeof (CHAR16);
 | 
						|
    } 
 | 
						|
    CopyMem (*FileName + Length, NodeStr, NodeStrLength);
 | 
						|
    Length += NodeStrLength;
 | 
						|
    
 | 
						|
    LastNodeChar  = (CHAR16) ReadUnaligned16 ((UINT16 *) (NodeStr + NodeStrLength - sizeof(CHAR16)));
 | 
						|
    TmpDevicePath = NextDevicePathNode (TmpDevicePath);
 | 
						|
  }    
 | 
						|
 | 
						|
  return Length;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the DevicePath2 is identical with DevicePath1, or identical with
 | 
						|
  DevicePath1's child device path.
 | 
						|
 | 
						|
  If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device
 | 
						|
  path, then TRUE returned. Otherwise, FALSE is returned.
 | 
						|
  
 | 
						|
  If DevicePath1 is NULL, then ASSERT().
 | 
						|
  If DevicePath2 is NULL, then ASSERT().
 | 
						|
 | 
						|
  @param[in]  DevicePath1   A pointer to a device path.
 | 
						|
  @param[in]  DevicePath2   A pointer to a device path.
 | 
						|
 | 
						|
  @retval     TRUE          Two device paths are identical , or DevicePath2 is 
 | 
						|
                            DevicePath1's child device path.
 | 
						|
  @retval     FALSE         Two device paths are not identical, and DevicePath2 
 | 
						|
                            is not DevicePath1's child device path.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
CheckDevicePath (
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL          *DevicePath1,
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL          *DevicePath2
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                                       DevicePathSize;
 | 
						|
  UINTN                                       FileNameSize1;
 | 
						|
  UINTN                                       FileNameSize2;
 | 
						|
  UINT8                                       *FileName1;
 | 
						|
  UINT8                                       *FileName2;
 | 
						|
  UINTN                                       FileNameOffset1;
 | 
						|
  UINTN                                       FileNameOffset2;
 | 
						|
  BOOLEAN                                     DevicePathEqual;
 | 
						|
 | 
						|
  FileName1       = NULL;
 | 
						|
  FileName2       = NULL;
 | 
						|
  DevicePathEqual = TRUE;
 | 
						|
 | 
						|
  ASSERT (DevicePath1 != NULL);
 | 
						|
  ASSERT (DevicePath2 != NULL);
 | 
						|
  if (IsDevicePathEnd (DevicePath1)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // The file name may contain one or more device path node. 
 | 
						|
  // To compare the file name, copy file name to a buffer and compare the buffer.
 | 
						|
  //
 | 
						|
  FileNameSize1 = GetFileName (DevicePath1, &FileName1, &FileNameOffset1);
 | 
						|
  if (FileNameSize1 != 0) {
 | 
						|
    FileNameSize2 = GetFileName (DevicePath2, &FileName2, &FileNameOffset2);
 | 
						|
    if (FileNameOffset1 != FileNameOffset2) {
 | 
						|
      DevicePathEqual = FALSE;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
    if (CompareMem (DevicePath1, DevicePath2, FileNameOffset1) != 0) {      
 | 
						|
      DevicePathEqual = FALSE;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
    if (FileNameSize1 > FileNameSize2) {
 | 
						|
      DevicePathEqual = FALSE;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
    if (CompareMem (FileName1, FileName2, FileNameSize1) != 0) {      
 | 
						|
      DevicePathEqual = FALSE;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
    DevicePathEqual = TRUE;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  DevicePathSize = GetDevicePathSize (DevicePath1);
 | 
						|
  if (DevicePathSize > GetDevicePathSize (DevicePath2)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Exclude the end of device path node.
 | 
						|
  //
 | 
						|
  DevicePathSize -= sizeof (EFI_DEVICE_PATH_PROTOCOL);
 | 
						|
  if (CompareMem (DevicePath1, DevicePath2, DevicePathSize) != 0) {
 | 
						|
    DevicePathEqual = FALSE;
 | 
						|
  } 
 | 
						|
  
 | 
						|
Done: 
 | 
						|
  if (FileName1 != NULL) {
 | 
						|
    FreePool (FileName1);
 | 
						|
  }
 | 
						|
  if (FileName2 != NULL) {
 | 
						|
    FreePool (FileName2);
 | 
						|
  }
 | 
						|
  return DevicePathEqual;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the image pointed to by DevicePath is in the device path list 
 | 
						|
  specified by AccessType.  
 | 
						|
 | 
						|
  @param[in] DevicePath  Points to device path.
 | 
						|
  @param[in] AccessType  The type of user access control.
 | 
						|
 
 | 
						|
  @retval    TURE        The DevicePath is in the specified List.
 | 
						|
  @retval    FALSE       The DevicePath is not in the specified List.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsDevicePathInList (
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
 | 
						|
  IN        UINT32                     AccessType
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  EFI_USER_INFO_ACCESS_CONTROL          *Access;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL              *Path;
 | 
						|
  UINTN                                 OffSet;  
 | 
						|
 | 
						|
  Status = GetAccessControl (&Access, AccessType);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return FALSE;
 | 
						|
  }  
 | 
						|
 | 
						|
  OffSet = 0;
 | 
						|
  while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
 | 
						|
    Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet);    
 | 
						|
    if (CheckDevicePath (Path, DevicePath)) {
 | 
						|
      //
 | 
						|
      // The device path is found in list.
 | 
						|
      //
 | 
						|
      FreePool (Access);
 | 
						|
      return TRUE;
 | 
						|
    }  
 | 
						|
    OffSet += GetDevicePathSize (Path);
 | 
						|
  }
 | 
						|
  
 | 
						|
  FreePool (Access);
 | 
						|
  return FALSE; 
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the image pointed to by DevicePath is permitted to load.  
 | 
						|
 | 
						|
  @param[in] DevicePath  Points to device path
 | 
						|
 
 | 
						|
  @retval    TURE        The image pointed by DevicePath is permitted to load.
 | 
						|
  @retval    FALSE       The image pointed by DevicePath is forbidden to load.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
VerifyDevicePath (
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *DevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {
 | 
						|
    //
 | 
						|
    // This access control overrides any restrictions put in place by the 
 | 
						|
    // EFI_USER_INFO_ACCESS_FORBID_LOAD record.
 | 
						|
    //
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {
 | 
						|
    //
 | 
						|
    // The device path is found in the forbidden list.
 | 
						|
    //
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  
 | 
						|
  return TRUE; 
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check the image pointed by DevicePath is a boot option or not.  
 | 
						|
 | 
						|
  @param[in] DevicePath  Points to device path.
 | 
						|
 
 | 
						|
  @retval    TURE        The image pointed by DevicePath is a boot option.
 | 
						|
  @retval    FALSE       The image pointed by DevicePath is not a boot option.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsBootOption (
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL      *DevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  UINT16                            *BootOrderList;
 | 
						|
  UINTN                             BootOrderListSize;
 | 
						|
  UINTN                             Index;
 | 
						|
  CHAR16                            StrTemp[20];
 | 
						|
  UINT8                             *OptionBuffer;
 | 
						|
  UINT8                             *OptionPtr;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL          *OptionDevicePath;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Get BootOrder
 | 
						|
  //
 | 
						|
  BootOrderListSize = 0;
 | 
						|
  BootOrderList     = NULL;  
 | 
						|
  Status = gRT->GetVariable (
 | 
						|
                  L"BootOrder", 
 | 
						|
                  &gEfiGlobalVariableGuid, 
 | 
						|
                  NULL, 
 | 
						|
                  &BootOrderListSize, 
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
    BootOrderList = AllocateZeroPool (BootOrderListSize);
 | 
						|
    ASSERT (BootOrderList != NULL);
 | 
						|
    Status = gRT->GetVariable (
 | 
						|
                    L"BootOrder", 
 | 
						|
                    &gEfiGlobalVariableGuid, 
 | 
						|
                    NULL, 
 | 
						|
                    &BootOrderListSize, 
 | 
						|
                    BootOrderList
 | 
						|
                    );
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // No Boot option
 | 
						|
    //
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  OptionBuffer = NULL;
 | 
						|
  for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
 | 
						|
    //
 | 
						|
    // Try to find the DevicePath in BootOption
 | 
						|
    //
 | 
						|
    UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
 | 
						|
    GetEfiGlobalVariable2 (StrTemp, (VOID**)&OptionBuffer, NULL);
 | 
						|
    if (OptionBuffer == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check whether the image is forbidden.
 | 
						|
    //
 | 
						|
    
 | 
						|
    OptionPtr = OptionBuffer;
 | 
						|
    //
 | 
						|
    // Skip attribute.
 | 
						|
    //
 | 
						|
    OptionPtr += sizeof (UINT32);
 | 
						|
 | 
						|
    //
 | 
						|
    // Skip device path length.
 | 
						|
    //
 | 
						|
    OptionPtr += sizeof (UINT16);
 | 
						|
 | 
						|
    //
 | 
						|
    // Skip descript string
 | 
						|
    //
 | 
						|
    OptionPtr += StrSize ((UINT16 *) OptionPtr);
 | 
						|
 
 | 
						|
    //
 | 
						|
    // Now OptionPtr points to Device Path.
 | 
						|
    //
 | 
						|
    OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;
 | 
						|
 | 
						|
    if (CheckDevicePath (DevicePath, OptionDevicePath)) {
 | 
						|
      FreePool (OptionBuffer);
 | 
						|
      OptionBuffer = NULL;
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
    FreePool (OptionBuffer);
 | 
						|
    OptionBuffer = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BootOrderList != NULL) {
 | 
						|
    FreePool (BootOrderList);
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Add the image info to a deferred image list.
 | 
						|
 | 
						|
  @param[in]  ImageDevicePath  A pointer to the device path of a image.                                
 | 
						|
  @param[in]  Image            Points to the first byte of the image, or NULL if the 
 | 
						|
                               image is not available.
 | 
						|
  @param[in]  ImageSize        The size of the image, or 0 if the image is not available.
 | 
						|
  
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PutDefferedImageInfo (
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL    *ImageDevicePath,
 | 
						|
  IN        VOID                        *Image,
 | 
						|
  IN        UINTN                       ImageSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEFERRED_IMAGE_INFO    *CurImageInfo;
 | 
						|
  UINTN                  PathSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Expand memory for the new deferred image.
 | 
						|
  //
 | 
						|
  if (mDeferredImage.Count == 0) {
 | 
						|
    mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));
 | 
						|
    ASSERT (mDeferredImage.ImageInfo != NULL);
 | 
						|
  } else {
 | 
						|
    CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));
 | 
						|
    ASSERT (CurImageInfo != NULL);
 | 
						|
    
 | 
						|
    CopyMem (
 | 
						|
      CurImageInfo, 
 | 
						|
      mDeferredImage.ImageInfo,
 | 
						|
      mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)
 | 
						|
      );
 | 
						|
    FreePool (mDeferredImage.ImageInfo);
 | 
						|
    mDeferredImage.ImageInfo = CurImageInfo;
 | 
						|
  }
 | 
						|
  mDeferredImage.Count++;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Save the deferred image information.
 | 
						|
  //
 | 
						|
  CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];
 | 
						|
  PathSize     = GetDevicePathSize (ImageDevicePath);
 | 
						|
  CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);
 | 
						|
  ASSERT (CurImageInfo->ImageDevicePath != NULL);
 | 
						|
  CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);
 | 
						|
 | 
						|
  CurImageInfo->Image      = Image;
 | 
						|
  CurImageInfo->ImageSize  = ImageSize;
 | 
						|
  CurImageInfo->BootOption = IsBootOption (ImageDevicePath);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEFERRED_IMAGE_INFO   *ReqImageInfo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the parameter.
 | 
						|
  //
 | 
						|
 | 
						|
  if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  
 | 
						|
  if ((ImageDevicePath == NULL) || (BootOption == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (ImageIndex >= mDeferredImage.Count) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Get the request deferred image.
 | 
						|
  // 
 | 
						|
  ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];
 | 
						|
   
 | 
						|
  *ImageDevicePath = ReqImageInfo->ImageDevicePath;
 | 
						|
  *Image           = ReqImageInfo->Image;
 | 
						|
  *ImageSize       = ReqImageInfo->ImageSize;
 | 
						|
  *BootOption      = ReqImageInfo->BootOption;
 | 
						|
  
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Provides the service of deferring image load based on platform policy control,
 | 
						|
  and installs Deferred Image Load Protocol.
 | 
						|
 | 
						|
  @param[in]  AuthenticationStatus  This is the authentication status returned from the 
 | 
						|
                                    security measurement services for the input file.
 | 
						|
  @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]  FileBuffer            File buffer matches the input file device path.
 | 
						|
  @param[in]  FileSize              Size of File buffer matches the input file device path.
 | 
						|
  @param[in]  BootPolicy            A boot policy that was used to call LoadImage() UEFI service.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS               FileBuffer is NULL and current user has permission to start
 | 
						|
                                    UEFI device drivers on the device path specified by DevicePath.
 | 
						|
  @retval EFI_SUCCESS               The file specified by DevicePath and non-NULL
 | 
						|
                                    FileBuffer did authenticate, and the platform policy dictates
 | 
						|
                                    that the DXE Foundation may use the file.
 | 
						|
  @retval EFI_SECURITY_VIOLATION    FileBuffer is NULL and the user has no
 | 
						|
                                    permission to start UEFI device drivers on the device path specified
 | 
						|
                                    by DevicePath.
 | 
						|
  @retval EFI_SECURITY_VIOLATION    FileBuffer is not NULL and the user has no permission to load
 | 
						|
                                    drivers from the device path specified by DevicePath. The
 | 
						|
                                    image has been added into the list of the deferred images.
 | 
						|
  @retval EFI_ACCESS_DENIED         The file specified by File and FileBuffer did not
 | 
						|
                                    authenticate, and the platform policy dictates that the DXE
 | 
						|
                                    Foundation many not use File.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DxeDeferImageLoadHandler (
 | 
						|
  IN  UINT32                           AuthenticationStatus,
 | 
						|
  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,
 | 
						|
  IN  VOID                             *FileBuffer,
 | 
						|
  IN  UINTN                            FileSize,
 | 
						|
  IN  BOOLEAN                          BootPolicy
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  EFI_USER_PROFILE_HANDLE              CurrentUser;
 | 
						|
  UINT32                               Policy;
 | 
						|
  UINT32                               FileType;
 | 
						|
 | 
						|
  //
 | 
						|
  // Ignore if File is NULL.
 | 
						|
  //
 | 
						|
  if (File == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether user has a logon.
 | 
						|
  // 
 | 
						|
  CurrentUser = NULL;
 | 
						|
  if (mUserManager != NULL) {
 | 
						|
    mUserManager->Current (mUserManager, &CurrentUser);
 | 
						|
    if (CurrentUser != NULL) {
 | 
						|
      //
 | 
						|
      // The user is logon; verify the FilePath by current user access policy.
 | 
						|
      //
 | 
						|
      if (!VerifyDevicePath (File)) {
 | 
						|
        DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));
 | 
						|
        return EFI_SECURITY_VIOLATION;
 | 
						|
      }
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Still no user logon.
 | 
						|
  // Check the file type and get policy setting.
 | 
						|
  //
 | 
						|
  FileType = GetFileType (File);
 | 
						|
  Policy   = PcdGet32 (PcdDeferImageLoadPolicy);
 | 
						|
  if ((Policy & FileType) == FileType) {
 | 
						|
    //
 | 
						|
    // This file type is secure to load.
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 
 | 
						|
  DEBUG ((EFI_D_ERROR, "[Security] No user identified, the image is deferred to load!\n"));
 | 
						|
  PutDefferedImageInfo (File, FileBuffer, FileSize);
 | 
						|
 | 
						|
  //
 | 
						|
  // Install the Deferred Image Load Protocol onto a new handle.
 | 
						|
  //
 | 
						|
  if (!mIsProtocolInstalled) {
 | 
						|
    Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                    &mDeferredImageHandle,
 | 
						|
                    &gEfiDeferredImageLoadProtocolGuid,
 | 
						|
                    &gDeferredImageLoad,
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
    mIsProtocolInstalled = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_ACCESS_DENIED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Locate user manager protocol when user manager is installed.  
 | 
						|
 | 
						|
  @param[in] Event    The Event that is being processed, not used.
 | 
						|
  @param[in] Context  Event Context, not used. 
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
FindUserManagerProtocol (
 | 
						|
  IN EFI_EVENT    Event,
 | 
						|
  IN VOID*        Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  gBS->LocateProtocol (
 | 
						|
         &gEfiUserManagerProtocolGuid,
 | 
						|
         NULL,
 | 
						|
         (VOID **) &mUserManager
 | 
						|
         );
 | 
						|
  
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Register security handler for deferred image load.
 | 
						|
 | 
						|
  @param[in]  ImageHandle   ImageHandle of the loaded driver.
 | 
						|
  @param[in]  SystemTable   Pointer to the EFI System Table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The handlers were registered successfully.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DxeDeferImageLoadLibConstructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID                 *Registration;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Register user manager notification function.
 | 
						|
  //
 | 
						|
  EfiCreateProtocolNotifyEvent (
 | 
						|
    &gEfiUserManagerProtocolGuid, 
 | 
						|
    TPL_CALLBACK,
 | 
						|
    FindUserManagerProtocol,
 | 
						|
    NULL,
 | 
						|
    &Registration
 | 
						|
    );
 | 
						|
  
 | 
						|
  return RegisterSecurity2Handler (
 | 
						|
           DxeDeferImageLoadHandler,
 | 
						|
           EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD 
 | 
						|
           );      
 | 
						|
}
 | 
						|
 | 
						|
 |