summaryrefslogtreecommitdiff
path: root/SecurityPkg/Library/DxeDeferImageLoadLib
diff options
context:
space:
mode:
authorgdong1 <gdong1@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-02 07:49:32 +0000
committergdong1 <gdong1@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-02 07:49:32 +0000
commit0c18794ea4289f03fefc7117b56740414cc0536c (patch)
tree4e51c5cc23c69a67cead8c58464da870daa4c029 /SecurityPkg/Library/DxeDeferImageLoadLib
parent986d1dfb0813d6a7623531e85c2e2a7e1f956cf8 (diff)
downloadedk2-platforms-0c18794ea4289f03fefc7117b56740414cc0536c.tar.xz
Add security package to repository.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12261 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'SecurityPkg/Library/DxeDeferImageLoadLib')
-rw-r--r--SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c858
-rw-r--r--SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h106
-rw-r--r--SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf62
3 files changed, 1026 insertions, 0 deletions
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
new file mode 100644
index 0000000000..f7fe594060
--- /dev/null
+++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
@@ -0,0 +1,858 @@
+/** @file
+ Implement defer image load services for user identification in UEFI2.2.
+
+Copyright (c) 2009 - 2011, 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;
+}
+
+
+/**
+ Convert the '/' to '\' in the specified string.
+
+ @param[in, out] Str Points to the string to convert.
+
+**/
+VOID
+ConvertDPStr (
+ IN OUT EFI_STRING Str
+ )
+{
+ INTN Count;
+ INTN Index;
+
+ Count = StrSize(Str) / 2 - 1;
+
+ if (Count < 4) {
+ return;
+ }
+
+ //
+ // Convert device path string.
+ //
+ Index = Count - 1;
+ while (Index > 0) {
+ //
+ // Find the last '/'.
+ //
+ for (Index = Count - 1; Index > 0; Index--) {
+ if (Str[Index] == L'/')
+ break;
+ }
+
+ //
+ // Check next char.
+ //
+ if (Str[Index + 1] == L'\\')
+ return;
+
+ Str[Index] = L'\\';
+
+ //
+ // Check previous char.
+ //
+ if ((Index > 0) && (Str[Index - 1] == L'\\')) {
+ CopyMem (&Str[Index - 1], &Str[Index], (UINTN) ((Count - Index + 1) * sizeof (CHAR16)));
+ return;
+ }
+ Index--;
+ }
+}
+
+
+/**
+ 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
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING DevicePathStr1;
+ EFI_STRING DevicePathStr2;
+ UINTN StrLen1;
+ UINTN StrLen2;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathText;
+ BOOLEAN DevicePathEqual;
+
+ ASSERT (DevicePath1 != NULL);
+ ASSERT (DevicePath2 != NULL);
+
+ DevicePathEqual = FALSE;
+ DevicePathText = NULL;
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **) &DevicePathText
+ );
+ ASSERT (Status == EFI_SUCCESS);
+
+ //
+ // Get first device path string.
+ //
+ DevicePathStr1 = DevicePathText->ConvertDevicePathToText (DevicePath1, TRUE, TRUE);
+ ConvertDPStr (DevicePathStr1);
+ //
+ // Get second device path string.
+ //
+ DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE);
+ ConvertDPStr (DevicePathStr2);
+
+ //
+ // Compare device path string.
+ //
+ StrLen1 = StrSize (DevicePathStr1);
+ StrLen2 = StrSize (DevicePathStr2);
+ if (StrLen1 > StrLen2) {
+ DevicePathEqual = FALSE;
+ goto Done;
+ }
+
+ if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) {
+ DevicePathEqual = TRUE;
+ }
+
+Done:
+ FreePool (DevicePathStr1);
+ FreePool (DevicePathStr2);
+ 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);
+ OptionBuffer = GetEfiGlobalVariable (StrTemp);
+ 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.
+
+ @retval EFI_SUCCESS The file specified by File did authenticate, and the
+ platform policy dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeDeferImageLoadHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ UINT32 Policy;
+ UINT32 FileType;
+
+ if (File == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 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_ACCESS_DENIED;
+ }
+ 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, NULL, 0);
+
+ //
+ // 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 RegisterSecurityHandler (
+ DxeDeferImageLoadHandler,
+ EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD
+ );
+}
+
+
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h
new file mode 100644
index 0000000000..52eb81b796
--- /dev/null
+++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h
@@ -0,0 +1,106 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by DeferImageLoadLib.
+
+Copyright (c) 2009 - 2010, 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.
+
+**/
+
+#ifndef __DEFER_IMAGE_LOAD_LIB_H__
+#define __DEFER_IMAGE_LOAD_LIB_H__
+
+#include <PiDxe.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DeferredImageLoad.h>
+#include <Protocol/UserCredential.h>
+#include <Protocol/UserManager.h>
+#include <Protocol/DevicePathToText.h>
+
+#include <Guid/GlobalVariable.h>
+
+//
+// Image type definitions.
+//
+#define IMAGE_UNKNOWN 0x00000001
+#define IMAGE_FROM_FV 0x00000002
+#define IMAGE_FROM_OPTION_ROM 0x00000004
+#define IMAGE_FROM_REMOVABLE_MEDIA 0x00000008
+#define IMAGE_FROM_FIXED_MEDIA 0x00000010
+
+//
+// The struct to save the deferred image information.
+//
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
+ VOID *Image;
+ UINTN ImageSize;
+ BOOLEAN BootOption;
+} DEFERRED_IMAGE_INFO;
+
+//
+// The table to save the deferred image item.
+//
+typedef struct {
+ UINTN Count; ///< deferred image count
+ DEFERRED_IMAGE_INFO *ImageInfo; ///< deferred image item
+} DEFERRED_IMAGE_TABLE;
+
+/**
+ 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 called successfully.
+ @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
+ );
+
+#endif
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
new file mode 100644
index 0000000000..e16fe8dc04
--- /dev/null
+++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
@@ -0,0 +1,62 @@
+## @file
+# The library instance provides security service of deferring image load.
+#
+# Copyright (c) 2009 - 2010, 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeDeferImageLoadLib
+ FILE_GUID = 5E2FAE1F-41DA-4fbd-BC81-603CE5CD8497
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = DxeDeferImageLoadLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeDeferImageLoadLib.c
+ DxeDeferImageLoadLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ SecurityManagementLib
+ MemoryAllocationLib
+ DevicePathLib
+ BaseMemoryLib
+ PrintLib
+ DebugLib
+ UefiLib
+ PcdLib
+
+[Protocols]
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiUserManagerProtocolGuid
+ gEfiDeferredImageLoadProtocolGuid
+ gEfiDevicePathToTextProtocolGuid
+
+[Guids]
+ gEfiGlobalVariableGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy