/** @file | |
Supports Fmp Capsule Dependency Expression. | |
Copyright (c) Microsoft Corporation.<BR> | |
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <PiDxe.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/FmpDependencyLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Guid/SystemResourceTable.h> | |
#include <LastAttemptStatus.h> | |
#include <FmpLastAttemptStatus.h> | |
// | |
// Define the initial size of the dependency expression evaluation stack | |
// | |
#define DEPEX_STACK_SIZE_INCREMENT 0x1000 | |
// | |
// Type of stack element | |
// | |
typedef enum { | |
BooleanType, | |
VersionType | |
} ELEMENT_TYPE; | |
// | |
// Value of stack element | |
// | |
typedef union { | |
BOOLEAN Boolean; | |
UINT32 Version; | |
} ELEMENT_VALUE; | |
// | |
// Stack element used to evaluate dependency expressions | |
// | |
typedef struct { | |
ELEMENT_VALUE Value; | |
ELEMENT_TYPE Type; | |
} DEPEX_ELEMENT; | |
// | |
// Global stack used to evaluate dependency expressions | |
// | |
DEPEX_ELEMENT *mDepexEvaluationStack = NULL; | |
DEPEX_ELEMENT *mDepexEvaluationStackEnd = NULL; | |
DEPEX_ELEMENT *mDepexEvaluationStackPointer = NULL; | |
/** | |
Grow size of the Depex stack | |
@retval EFI_SUCCESS Stack successfully growed. | |
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. | |
**/ | |
EFI_STATUS | |
GrowDepexStack ( | |
VOID | |
) | |
{ | |
DEPEX_ELEMENT *NewStack; | |
UINTN Size; | |
Size = DEPEX_STACK_SIZE_INCREMENT; | |
if (mDepexEvaluationStack != NULL) { | |
Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack); | |
} | |
NewStack = AllocatePool (Size * sizeof (DEPEX_ELEMENT)); | |
if (NewStack == NULL) { | |
DEBUG ((DEBUG_ERROR, "GrowDepexStack: Cannot allocate memory for dependency evaluation stack!\n")); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
if (mDepexEvaluationStack != NULL) { | |
// | |
// Copy to Old Stack to the New Stack | |
// | |
CopyMem ( | |
NewStack, | |
mDepexEvaluationStack, | |
(mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (DEPEX_ELEMENT) | |
); | |
// | |
// Free The Old Stack | |
// | |
FreePool (mDepexEvaluationStack); | |
} | |
// | |
// Make the Stack pointer point to the old data in the new stack | |
// | |
mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack); | |
mDepexEvaluationStack = NewStack; | |
mDepexEvaluationStackEnd = NewStack + Size; | |
return EFI_SUCCESS; | |
} | |
/** | |
Push an element onto the Stack. | |
@param[in] Value Value to push. | |
@param[in] Type Element Type | |
@retval EFI_SUCCESS The value was pushed onto the stack. | |
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. | |
@retval EFI_INVALID_PARAMETER Wrong stack element type. | |
**/ | |
EFI_STATUS | |
Push ( | |
IN UINT32 Value, | |
IN UINTN Type | |
) | |
{ | |
EFI_STATUS Status; | |
DEPEX_ELEMENT Element; | |
// | |
// Check Type | |
// | |
if ((Type != BooleanType) && (Type != VersionType)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Check for a stack overflow condition | |
// | |
if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) { | |
// | |
// Grow the stack | |
// | |
Status = GrowDepexStack (); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} | |
Element.Value.Version = Value; | |
Element.Type = Type; | |
// | |
// Push the item onto the stack | |
// | |
*mDepexEvaluationStackPointer = Element; | |
mDepexEvaluationStackPointer++; | |
return EFI_SUCCESS; | |
} | |
/** | |
Pop an element from the stack. | |
@param[out] Element Element to pop. | |
@param[in] Type Type of element. | |
@retval EFI_SUCCESS The value was popped onto the stack. | |
@retval EFI_ACCESS_DENIED The pop operation underflowed the stack. | |
@retval EFI_INVALID_PARAMETER Type is mismatched. | |
**/ | |
EFI_STATUS | |
Pop ( | |
OUT DEPEX_ELEMENT *Element, | |
IN ELEMENT_TYPE Type | |
) | |
{ | |
// | |
// Check for a stack underflow condition | |
// | |
if (mDepexEvaluationStackPointer == mDepexEvaluationStack) { | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: Stack underflow!\n")); | |
return EFI_ACCESS_DENIED; | |
} | |
// | |
// Pop the item off the stack | |
// | |
mDepexEvaluationStackPointer--; | |
*Element = *mDepexEvaluationStackPointer; | |
if ((*Element).Type != Type) { | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: Popped element type is mismatched!\n")); | |
return EFI_INVALID_PARAMETER; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Evaluate the dependencies. The caller must search all the Fmp instances and | |
gather their versions into FmpVersions parameter. If there is PUSH_GUID opcode | |
in dependency expression with no FmpVersions provided, the dependency will | |
evaluate to FALSE. | |
@param[in] Dependencies Dependency expressions. | |
@param[in] DependenciesSize Size of Dependency expressions. | |
@param[in] FmpVersions Array of Fmp ImageTypeId and version. This | |
parameter is optional and can be set to NULL. | |
@param[in] FmpVersionsCount Element count of the array. When FmpVersions | |
is NULL, FmpVersionsCount must be 0. | |
@param[out] LastAttemptStatus An optional pointer to a UINT32 that holds the | |
last attempt status to report back to the caller. | |
This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS | |
if an error code is not set. | |
@retval TRUE Dependency expressions evaluate to TRUE. | |
@retval FALSE Dependency expressions evaluate to FALSE. | |
**/ | |
BOOLEAN | |
EFIAPI | |
EvaluateDependency ( | |
IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, | |
IN UINTN DependenciesSize, | |
IN FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions OPTIONAL, | |
IN UINTN FmpVersionsCount, | |
OUT UINT32 *LastAttemptStatus OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
UINT8 *Iterator; | |
UINT8 Index; | |
DEPEX_ELEMENT Element1; | |
DEPEX_ELEMENT Element2; | |
GUID ImageTypeId; | |
UINT32 Version; | |
UINT32 LocalLastAttemptStatus; | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; | |
// | |
// Check if parameter is valid. | |
// | |
if ((Dependencies == NULL) || (DependenciesSize == 0)) { | |
return FALSE; | |
} | |
if ((FmpVersions == NULL) && (FmpVersionsCount > 0)) { | |
return FALSE; | |
} | |
// | |
// Clean out memory leaks in Depex Boolean stack. Leaks are only caused by | |
// incorrectly formed DEPEX expressions | |
// | |
mDepexEvaluationStackPointer = mDepexEvaluationStack; | |
Iterator = (UINT8 *)Dependencies->Dependencies; | |
while (Iterator < (UINT8 *)Dependencies->Dependencies + DependenciesSize) { | |
switch (*Iterator) { | |
case EFI_FMP_DEP_PUSH_GUID: | |
if (Iterator + sizeof (EFI_GUID) >= (UINT8 *)Dependencies->Dependencies + DependenciesSize) { | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: GUID extends beyond end of dependency expression!\n")); | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GUID_BEYOND_DEPEX; | |
goto Error; | |
} | |
CopyGuid (&ImageTypeId, (EFI_GUID *)(Iterator + 1)); | |
Iterator = Iterator + sizeof (EFI_GUID); | |
for (Index = 0; Index < FmpVersionsCount; Index++) { | |
if (CompareGuid (&FmpVersions[Index].ImageTypeId, &ImageTypeId)) { | |
Status = Push (FmpVersions[Index].Version, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
} | |
} | |
if (Index == FmpVersionsCount) { | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: %g is not found!\n", &ImageTypeId)); | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_FMP_NOT_FOUND; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_PUSH_VERSION: | |
if (Iterator + sizeof (UINT32) >= (UINT8 *)Dependencies->Dependencies + DependenciesSize ) { | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: VERSION extends beyond end of dependency expression!\n")); | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_BEYOND_DEPEX; | |
goto Error; | |
} | |
Version = *(UINT32 *)(Iterator + 1); | |
Status = Push (Version, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
Iterator = Iterator + sizeof (UINT32); | |
break; | |
case EFI_FMP_DEP_VERSION_STR: | |
Iterator += AsciiStrnLenS ((CHAR8 *)Iterator, DependenciesSize - (Iterator - Dependencies->Dependencies)); | |
if (Iterator == (UINT8 *)Dependencies->Dependencies + DependenciesSize) { | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: STRING extends beyond end of dependency expression!\n")); | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_STR_BEYOND_DEPEX; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_AND: | |
Status = Pop (&Element1, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Pop (&Element2, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Push (Element1.Value.Boolean & Element2.Value.Boolean, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_OR: | |
Status = Pop (&Element1, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Pop (&Element2, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Push (Element1.Value.Boolean | Element2.Value.Boolean, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_NOT: | |
Status = Pop (&Element1, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Push (!(Element1.Value.Boolean), BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_TRUE: | |
Status = Push (TRUE, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_FALSE: | |
Status = Push (FALSE, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_EQ: | |
Status = Pop (&Element1, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Pop (&Element2, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = (Element1.Value.Version == Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_GT: | |
Status = Pop (&Element1, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Pop (&Element2, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = (Element1.Value.Version > Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_GTE: | |
Status = Pop (&Element1, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Pop (&Element2, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = (Element1.Value.Version >= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_LT: | |
Status = Pop (&Element1, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Pop (&Element2, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = (Element1.Value.Version < Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_LTE: | |
Status = Pop (&Element1, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = Pop (&Element2, VersionType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
Status = (Element1.Value.Version <= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE; | |
goto Error; | |
} | |
break; | |
case EFI_FMP_DEP_END: | |
Status = Pop (&Element1, BooleanType); | |
if (EFI_ERROR (Status)) { | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE; | |
goto Error; | |
} | |
return Element1.Value.Boolean; | |
default: | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: Unknown Opcode - %02x!\n", *Iterator)); | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_UNKNOWN_OPCODE; | |
goto Error; | |
} | |
Iterator++; | |
} | |
DEBUG ((DEBUG_ERROR, "EvaluateDependency: No EFI_FMP_DEP_END Opcode in expression!\n")); | |
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE; | |
Error: | |
if (LastAttemptStatus != NULL) { | |
*LastAttemptStatus = LocalLastAttemptStatus; | |
} | |
return FALSE; | |
} | |
/** | |
Validate the dependency expression and output its size. | |
@param[in] Dependencies Pointer to the EFI_FIRMWARE_IMAGE_DEP. | |
@param[in] MaxDepexSize Max size of the dependency. | |
@param[out] DepexSize Size of dependency. | |
@param[out] LastAttemptStatus An optional pointer to a UINT32 that holds the | |
last attempt status to report back to the caller. | |
If a last attempt status error code is not returned, | |
this function will not modify the LastAttemptStatus value. | |
@retval TRUE The dependency expression is valid. | |
@retval FALSE The dependency expression is invalid. | |
**/ | |
BOOLEAN | |
EFIAPI | |
ValidateDependency ( | |
IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, | |
IN UINTN MaxDepexSize, | |
OUT UINT32 *DepexSize, | |
OUT UINT32 *LastAttemptStatus OPTIONAL | |
) | |
{ | |
UINT8 *Depex; | |
if (DepexSize != NULL) { | |
*DepexSize = 0; | |
} | |
if (Dependencies == NULL) { | |
return FALSE; | |
} | |
Depex = Dependencies->Dependencies; | |
while (Depex < Dependencies->Dependencies + MaxDepexSize) { | |
switch (*Depex) { | |
case EFI_FMP_DEP_PUSH_GUID: | |
Depex += sizeof (EFI_GUID) + 1; | |
break; | |
case EFI_FMP_DEP_PUSH_VERSION: | |
Depex += sizeof (UINT32) + 1; | |
break; | |
case EFI_FMP_DEP_VERSION_STR: | |
Depex += AsciiStrnLenS ((CHAR8 *)Depex, Dependencies->Dependencies + MaxDepexSize - Depex) + 1; | |
break; | |
case EFI_FMP_DEP_AND: | |
case EFI_FMP_DEP_OR: | |
case EFI_FMP_DEP_NOT: | |
case EFI_FMP_DEP_TRUE: | |
case EFI_FMP_DEP_FALSE: | |
case EFI_FMP_DEP_EQ: | |
case EFI_FMP_DEP_GT: | |
case EFI_FMP_DEP_GTE: | |
case EFI_FMP_DEP_LT: | |
case EFI_FMP_DEP_LTE: | |
Depex += 1; | |
break; | |
case EFI_FMP_DEP_END: | |
Depex += 1; | |
if (DepexSize != NULL) { | |
*DepexSize = (UINT32)(Depex - Dependencies->Dependencies); | |
} | |
return TRUE; | |
default: | |
return FALSE; | |
} | |
} | |
if (LastAttemptStatus != NULL) { | |
*LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE; | |
} | |
return FALSE; | |
} | |
/** | |
Get dependency from firmware image. | |
@param[in] Image Points to the firmware image. | |
@param[in] ImageSize Size, in bytes, of the firmware image. | |
@param[out] DepexSize Size, in bytes, of the dependency. | |
@param[out] LastAttemptStatus An optional pointer to a UINT32 that holds the | |
last attempt status to report back to the caller. | |
If a last attempt status error code is not returned, | |
this function will not modify the LastAttemptStatus value. | |
@retval The pointer to dependency. | |
@retval Null | |
**/ | |
EFI_FIRMWARE_IMAGE_DEP * | |
EFIAPI | |
GetImageDependency ( | |
IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, | |
IN UINTN ImageSize, | |
OUT UINT32 *DepexSize, | |
OUT UINT32 *LastAttemptStatus OPTIONAL | |
) | |
{ | |
EFI_FIRMWARE_IMAGE_DEP *Depex; | |
UINTN MaxDepexSize; | |
if (Image == NULL) { | |
return NULL; | |
} | |
// | |
// Check to make sure that operation can be safely performed. | |
// | |
if ((((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) < (UINTN)Image) || \ | |
(((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize)) | |
{ | |
// | |
// Pointer overflow. Invalid image. | |
// | |
if (LastAttemptStatus != NULL) { | |
*LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GET_DEPEX_FAILURE; | |
} | |
return NULL; | |
} | |
Depex = (EFI_FIRMWARE_IMAGE_DEP *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength); | |
MaxDepexSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength); | |
// | |
// Validate the dependency and get the size of dependency | |
// | |
if (ValidateDependency (Depex, MaxDepexSize, DepexSize, LastAttemptStatus)) { | |
return Depex; | |
} | |
return NULL; | |
} |