/** @file\r
Implement defer image load services for user identification in UEFI2.2.\r
\r
-Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2014, 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
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
+ if (Access->Type == AccessType) {\r
*AccessControl = AllocateZeroPool (Access->Size);\r
ASSERT (*AccessControl != NULL);\r
CopyMem (*AccessControl, Access, Access->Size);\r
return EFI_NOT_FOUND;\r
}\r
\r
-\r
/**\r
- Convert the '/' to '\' in the specified string.\r
+ Get file name from device path.\r
\r
- @param[in, out] Str Points to the string to convert.\r
+ The file name may contain one or more device path node. Save the file name in a \r
+ buffer if file name is found. The caller is responsible to free the buffer. \r
+ \r
+ @param[in] DevicePath A pointer to a device path.\r
+ @param[out] FileName The callee allocated buffer to save the file name if file name is found.\r
+ @param[out] FileNameOffset The offset of file name in device path if file name is found.\r
+ \r
+ @retval UINTN The file name length. 0 means file name is not found.\r
\r
**/\r
-VOID\r
-ConvertDPStr (\r
- IN OUT EFI_STRING Str \r
+UINTN \r
+GetFileName (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT8 **FileName,\r
+ OUT UINTN *FileNameOffset\r
)\r
{\r
- INTN Count;\r
- INTN Index;\r
- \r
- Count = StrSize(Str) / 2 - 1;\r
+ UINTN Length;\r
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r
+ CHAR8 *NodeStr;\r
+ UINTN NodeStrLength;\r
+ CHAR16 LastNodeChar;\r
+ CHAR16 FirstNodeChar;\r
\r
- if (Count < 4) {\r
- return;\r
+ //\r
+ // Get the length of DevicePath before file name.\r
+ //\r
+ Length = 0;\r
+ RootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
+ while (!IsDevicePathEnd (RootDevicePath)) {\r
+ if ((DevicePathType(RootDevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType(RootDevicePath) == MEDIA_FILEPATH_DP)) {\r
+ break;\r
+ }\r
+ Length += DevicePathNodeLength (RootDevicePath);\r
+ RootDevicePath = NextDevicePathNode (RootDevicePath);\r
}\r
- \r
+\r
+ *FileNameOffset = Length;\r
+ if (Length == 0) {\r
+ return 0;\r
+ }\r
+\r
//\r
- // Convert device path string.\r
+ // Get the file name length.\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
+ Length = 0;\r
+ TmpDevicePath = RootDevicePath;\r
+ while (!IsDevicePathEnd (TmpDevicePath)) {\r
+ if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r
+ break;\r
}\r
+ Length += DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+ }\r
+ if (Length == 0) {\r
+ return 0;\r
+ }\r
\r
- //\r
- // Check next char.\r
- //\r
- if (Str[Index + 1] == L'\\')\r
- return;\r
+ *FileName = AllocateZeroPool (Length);\r
+ ASSERT (*FileName != NULL);\r
+\r
+ //\r
+ // Copy the file name to the buffer.\r
+ //\r
+ Length = 0;\r
+ LastNodeChar = '\\';\r
+ TmpDevicePath = RootDevicePath;\r
+ while (!IsDevicePathEnd (TmpDevicePath)) {\r
+ if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r
+ break;\r
+ }\r
+\r
+ FirstNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *)((UINT8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r
+ NodeStr = (CHAR8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+ NodeStrLength = DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL) - sizeof(CHAR16);\r
\r
- Str[Index] = L'\\';\r
+ if ((FirstNodeChar == '\\') && (LastNodeChar == '\\')) {\r
+ //\r
+ // Skip separator "\" when there are two separators.\r
+ //\r
+ NodeStr += sizeof (CHAR16);\r
+ NodeStrLength -= sizeof (CHAR16); \r
+ } else if ((FirstNodeChar != '\\') && (LastNodeChar != '\\')) {\r
+ //\r
+ // Add separator "\" when there is no separator.\r
+ //\r
+ WriteUnaligned16 ((UINT16 *)(*FileName + Length), '\\');\r
+ Length += sizeof (CHAR16);\r
+ } \r
+ CopyMem (*FileName + Length, NodeStr, NodeStrLength);\r
+ Length += NodeStrLength;\r
\r
- //\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
+ LastNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *) (NodeStr + NodeStrLength - sizeof(CHAR16)));\r
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+ } \r
+\r
+ return Length;\r
}\r
\r
\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
+ UINTN DevicePathSize;\r
+ UINTN FileNameSize1;\r
+ UINTN FileNameSize2;\r
+ UINT8 *FileName1;\r
+ UINT8 *FileName2;\r
+ UINTN FileNameOffset1;\r
+ UINTN FileNameOffset2;\r
+ BOOLEAN DevicePathEqual;\r
+\r
+ FileName1 = NULL;\r
+ FileName2 = NULL;\r
+ DevicePathEqual = TRUE;\r
\r
ASSERT (DevicePath1 != NULL);\r
ASSERT (DevicePath2 != NULL);\r
+ if (IsDevicePathEnd (DevicePath1)) {\r
+ return FALSE;\r
+ }\r
\r
- 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
+ // The file name may contain one or more device path node. \r
+ // To compare the file name, copy file name to a buffer and compare the buffer.\r
//\r
- // Get second device path string.\r
- //\r
- DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE);\r
- ConvertDPStr (DevicePathStr2);\r
- \r
+ FileNameSize1 = GetFileName (DevicePath1, &FileName1, &FileNameOffset1);\r
+ if (FileNameSize1 != 0) {\r
+ FileNameSize2 = GetFileName (DevicePath2, &FileName2, &FileNameOffset2);\r
+ if (FileNameOffset1 != FileNameOffset2) {\r
+ DevicePathEqual = FALSE;\r
+ goto Done;\r
+ }\r
+ if (CompareMem (DevicePath1, DevicePath2, FileNameOffset1) != 0) { \r
+ DevicePathEqual = FALSE;\r
+ goto Done;\r
+ }\r
+ if (FileNameSize1 > FileNameSize2) {\r
+ DevicePathEqual = FALSE;\r
+ goto Done;\r
+ }\r
+ if (CompareMem (FileName1, FileName2, FileNameSize1) != 0) { \r
+ DevicePathEqual = FALSE;\r
+ goto Done;\r
+ }\r
+ DevicePathEqual = TRUE;\r
+ goto Done;\r
+ }\r
+\r
+ DevicePathSize = GetDevicePathSize (DevicePath1);\r
+ if (DevicePathSize > GetDevicePathSize (DevicePath2)) {\r
+ return FALSE;\r
+ }\r
+\r
//\r
- // Compare device path string.\r
+ // Exclude the end of device path node.\r
//\r
- StrLen1 = StrSize (DevicePathStr1);\r
- StrLen2 = StrSize (DevicePathStr2);\r
- if (StrLen1 > StrLen2) {\r
+ DevicePathSize -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+ if (CompareMem (DevicePath1, DevicePath2, DevicePathSize) != 0) {\r
DevicePathEqual = FALSE;\r
- goto Done;\r
- }\r
+ } \r
\r
- if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) {\r
- DevicePathEqual = TRUE;\r
+Done: \r
+ if (FileName1 != NULL) {\r
+ FreePool (FileName1);\r
+ }\r
+ if (FileName2 != NULL) {\r
+ FreePool (FileName2);\r
}\r
-\r
-Done:\r
- FreePool (DevicePathStr1);\r
- FreePool (DevicePathStr2);\r
return DevicePathEqual;\r
}\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 TRUE The DevicePath is in the specified List.\r
@retval FALSE The DevicePath is not in the specified List.\r
\r
**/\r
\r
@param[in] DevicePath Points to device path\r
\r
- @retval TURE The image pointed by DevicePath is permitted to load.\r
+ @retval TRUE The image pointed by DevicePath is permitted to load.\r
@retval FALSE The image pointed by DevicePath is forbidden to load.\r
\r
**/\r
\r
@param[in] DevicePath Points to device path.\r
\r
- @retval TURE The image pointed by DevicePath is a boot option.\r
+ @retval TRUE The image pointed by DevicePath is a boot option.\r
@retval FALSE The image pointed by DevicePath is not a boot option.\r
\r
**/\r
// Try to find the DevicePath in BootOption\r
//\r
UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r
- GetEfiGlobalVariable2 (StrTemp, &OptionBuffer, NULL);\r
+ GetEfiGlobalVariable2 (StrTemp, (VOID**)&OptionBuffer, NULL);\r
if (OptionBuffer == NULL) {\r
continue;\r
}\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
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
+\r
+ @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start\r
+ UEFI device drivers on the device path specified by DevicePath.\r
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
+ FileBuffer did authenticate, and the platform policy dictates\r
+ that the DXE Foundation may use the file.\r
+ @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no\r
+ permission to start UEFI device drivers on the device path specified\r
+ by DevicePath.\r
+ @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load\r
+ drivers from the device path specified by DevicePath. The\r
+ image has been added into the list of the deferred images.\r
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
+ authenticate, and the platform policy dictates that the DXE\r
+ Foundation many not use File.\r
\r
**/\r
EFI_STATUS\r
IN UINT32 AuthenticationStatus,\r
IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
IN VOID *FileBuffer,\r
- IN UINTN FileSize\r
+ IN UINTN FileSize,\r
+ IN BOOLEAN BootPolicy\r
)\r
-\r
{\r
EFI_STATUS Status;\r
EFI_USER_PROFILE_HANDLE CurrentUser;\r
UINT32 Policy;\r
UINT32 FileType;\r
\r
+ //\r
+ // Ignore if File is NULL.\r
+ //\r
if (File == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
+ return EFI_SUCCESS;\r
}\r
\r
//\r
//\r
if (!VerifyDevicePath (File)) {\r
DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));\r
- return EFI_ACCESS_DENIED;\r
+ return EFI_SECURITY_VIOLATION;\r
}\r
return EFI_SUCCESS;\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
+ DEBUG ((EFI_D_INFO, "[Security] No user identified, the image is deferred to load!\n"));\r
+ PutDefferedImageInfo (File, FileBuffer, FileSize);\r
\r
//\r
// Install the Deferred Image Load Protocol onto a new handle.\r
&Registration\r
);\r
\r
- return RegisterSecurityHandler (\r
+ return RegisterSecurity2Handler (\r
DxeDeferImageLoadHandler,\r
EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \r
); \r