| /** @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; | |
| } |