diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.c b/FmpDevicePkg/FmpDxe/FmpDxe.c index b7fd9c93ae..de7f1fe53e 100644 --- a/FmpDevicePkg/FmpDxe/FmpDxe.c +++ b/FmpDevicePkg/FmpDxe/FmpDxe.c @@ -730,6 +730,15 @@ GetAllHeaderSize ( LAST_ATTEMPT_STATUS_DRIVER_MIN_ERROR_CODE_VALUE to LAST_ATTEMPT_STATUS_DRIVER_MAX_ERROR_CODE_VALUE. + This function might also return error codes that occur within libraries + linked against this module that return last attempt error codes such as: + + LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MIN_ERROR_CODE_VALUE to + LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MAX_ERROR_CODE_VALUE + + LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MIN_ERROR_CODE_VALUE to + LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MAX_ERROR_CODE_VALUE + @retval EFI_SUCCESS The image was successfully checked. @retval EFI_ABORTED The operation is aborted. @retval EFI_INVALID_PARAMETER The Image was NULL. @@ -925,7 +934,16 @@ CheckTheImageInternal ( // // Get the dependency from Image. // - Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize); + Dependencies = GetImageDependency ( + (EFI_FIRMWARE_IMAGE_AUTHENTICATION *) Image, + ImageSize, + &DependenciesSize, + LastAttemptStatus + ); + if (*LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) { + Status = EFI_ABORTED; + goto cleanup; + } // // Check the FmpPayloadHeader @@ -964,11 +982,18 @@ CheckTheImageInternal ( // // Evaluate dependency expression // - Private->DependenciesSatisfied = CheckFmpDependency (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize); + Private->DependenciesSatisfied = CheckFmpDependency ( + Private->Descriptor.ImageTypeId, + Version, + Dependencies, + DependenciesSize, + &LocalLastAttemptStatus + ); if (!Private->DependenciesSatisfied) { DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed.\n", mImageIdName)); *ImageUpdatable = IMAGE_UPDATABLE_INVALID; Status = EFI_SUCCESS; + *LastAttemptStatus = LocalLastAttemptStatus; goto cleanup; } @@ -1181,7 +1206,7 @@ SetTheImage ( // // Get the dependency from Image. // - Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize); + Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize, &LastAttemptStatus); // // No functional error in CheckTheImage. Attempt to get the Version to diff --git a/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h b/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h index ec380c4947..785bda9401 100644 --- a/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h +++ b/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h @@ -2,6 +2,7 @@ Fmp Capsule Dependency check functions for Firmware Management Protocol based firmware updates. + Copyright (c) Microsoft Corporation.
Copyright (c) 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -21,6 +22,10 @@ @param[in] Version New version. @param[in] Dependencies Fmp dependency. @param[in] DependenciesSize Size, in bytes, of the Fmp dependency. + @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 Dependencies are satisfied. @retval FALSE Dependencies are unsatisfied or dependency check fails. @@ -32,7 +37,8 @@ CheckFmpDependency ( IN EFI_GUID ImageTypeId, IN UINT32 Version, IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL - IN UINT32 DependenciesSize + IN UINT32 DependenciesSize, + OUT UINT32 *LastAttemptStatus OPTIONAL ); #endif diff --git a/FmpDevicePkg/Include/Library/FmpDependencyLib.h b/FmpDevicePkg/Include/Library/FmpDependencyLib.h index c732903425..f460f0f078 100644 --- a/FmpDevicePkg/Include/Library/FmpDependencyLib.h +++ b/FmpDevicePkg/Include/Library/FmpDependencyLib.h @@ -26,9 +26,13 @@ typedef struct { /** 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[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. @@ -39,16 +43,20 @@ EFIAPI ValidateDependency ( IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, IN UINTN MaxDepexSize, - OUT UINT32 *DepexSize + OUT UINT32 *DepexSize, + OUT UINT32 *LastAttemptStatus OPTIONAL ); /** 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[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 @@ -56,9 +64,10 @@ ValidateDependency ( EFI_FIRMWARE_IMAGE_DEP* EFIAPI GetImageDependency ( - IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, - IN UINTN ImageSize, - OUT UINT32 *DepexSize + IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, + IN UINTN ImageSize, + OUT UINT32 *DepexSize, + OUT UINT32 *LastAttemptStatus OPTIONAL ); /** @@ -73,6 +82,10 @@ GetImageDependency ( 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. @@ -81,10 +94,11 @@ GetImageDependency ( BOOLEAN EFIAPI EvaluateDependency ( - IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, - IN UINTN DependenciesSize, - IN FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions OPTIONAL, - IN UINTN FmpVersionsCount + IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, + IN UINTN DependenciesSize, + IN FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions, OPTIONAL + IN UINTN FmpVersionsCount, + OUT UINT32 *LastAttemptStatus OPTIONAL ); #endif diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c index 02ed600e0e..cca83dbe4a 100644 --- a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c +++ b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include /** Check dependency for firmware update. @@ -25,6 +28,10 @@ @param[in] Version New version. @param[in] Dependencies Fmp dependency. @param[in] DependenciesSize Size, in bytes, of the Fmp dependency. + @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 Dependencies are satisfied. @retval FALSE Dependencies are unsatisfied or dependency check fails. @@ -36,7 +43,8 @@ CheckFmpDependency ( IN EFI_GUID ImageTypeId, IN UINT32 Version, IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL - IN UINT32 DependenciesSize + IN UINT32 DependenciesSize, + OUT UINT32 *LastAttemptStatus OPTIONAL ) { EFI_STATUS Status; @@ -44,6 +52,7 @@ CheckFmpDependency ( UINTN Index; EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; UINTN ImageInfoSize; + UINT32 LocalLastAttemptStatus; UINT32 *DescriptorVer; UINT8 FmpImageInfoCount; UINTN *DescriptorSize; @@ -55,14 +64,15 @@ CheckFmpDependency ( UINTN FmpVersionsCount; BOOLEAN IsSatisfied; - FmpImageInfoBuf = NULL; - DescriptorVer = NULL; - DescriptorSize = NULL; - NumberOfFmpInstance = 0; - FmpVersions = NULL; - FmpVersionsCount = 0; - IsSatisfied = TRUE; - PackageVersionName = NULL; + LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + FmpImageInfoBuf = NULL; + DescriptorVer = NULL; + DescriptorSize = NULL; + NumberOfFmpInstance = 0; + FmpVersions = NULL; + FmpVersionsCount = 0; + IsSatisfied = TRUE; + PackageVersionName = NULL; // // Get ImageDescriptors of all FMP instances, and archive them for dependency evaluation. @@ -77,30 +87,35 @@ CheckFmpDependency ( if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "CheckFmpDependency: Get Firmware Management Protocol failed. (%r)", Status)); IsSatisfied = FALSE; + LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_FMP_PROTOCOL_NOT_FOUND; goto cleanup; } FmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfFmpInstance); if (FmpImageInfoBuf == NULL) { IsSatisfied = FALSE; + LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_FMP_INFO_BUFFER_FAILED; goto cleanup; } DescriptorVer = AllocateZeroPool (sizeof(UINT32) * NumberOfFmpInstance); if (DescriptorVer == NULL ) { IsSatisfied = FALSE; + LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_DESC_VER_BUFFER_FAILED; goto cleanup; } DescriptorSize = AllocateZeroPool (sizeof(UINTN) * NumberOfFmpInstance); if (DescriptorSize == NULL ) { IsSatisfied = FALSE; + LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_DESC_SIZE_BUFFER_FAILED; goto cleanup; } FmpVersions = AllocateZeroPool (sizeof(FMP_DEPEX_CHECK_VERSION_DATA) * NumberOfFmpInstance); if (FmpVersions == NULL) { IsSatisfied = FALSE; + LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_FMP_VER_BUFFER_FAILED; goto cleanup; } @@ -164,7 +179,7 @@ CheckFmpDependency ( // Evaluate firmware image's depex, against the version of other Fmp instances. // if (Dependencies != NULL) { - IsSatisfied = EvaluateDependency (Dependencies, DependenciesSize, FmpVersions, FmpVersionsCount); + IsSatisfied = EvaluateDependency (Dependencies, DependenciesSize, FmpVersions, FmpVersionsCount, &LocalLastAttemptStatus); } if (!IsSatisfied) { @@ -194,5 +209,9 @@ cleanup: FreePool (FmpVersions); } + if (LastAttemptStatus != NULL) { + *LastAttemptStatus = LocalLastAttemptStatus; + } + return IsSatisfied; } diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c index 55e9af2290..74247957ac 100644 --- a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c +++ b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c @@ -2,11 +2,13 @@ Null instance of FmpDependencyCheckLib. Copyright (c) 2020, Intel Corporation. All rights reserved.
+ Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include +#include #include /** @@ -16,7 +18,10 @@ @param[in] Version New version. @param[in] Dependencies Fmp dependency. @param[in] DependenciesSize Size, in bytes, of the Fmp dependency. - + @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 Dependencies are satisfied. @retval FALSE Dependencies are unsatisfied or dependency check fails. @@ -27,8 +32,13 @@ CheckFmpDependency ( IN EFI_GUID ImageTypeId, IN UINT32 Version, IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL - IN UINT32 DependenciesSize + IN UINT32 DependenciesSize, + OUT UINT32 *LastAttemptStatus OPTIONAL ) { + if (LastAttemptStatus != NULL) { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + } + return TRUE; } diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c index 5ef25d2415..b222ace6d6 100644 --- a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c +++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include // // Define the initial size of the dependency expression evaluation stack @@ -203,6 +206,10 @@ Pop ( 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. @@ -211,10 +218,11 @@ Pop ( BOOLEAN EFIAPI EvaluateDependency ( - IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, - IN UINTN DependenciesSize, - IN FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions OPTIONAL, - IN UINTN FmpVersionsCount + 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; @@ -224,6 +232,9 @@ EvaluateDependency ( DEPEX_ELEMENT Element2; GUID ImageTypeId; UINT32 Version; + UINT32 LocalLastAttemptStatus; + + LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; // // Check if parameter is valid. @@ -249,6 +260,7 @@ EvaluateDependency ( 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; } @@ -259,6 +271,7 @@ EvaluateDependency ( 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; @@ -266,18 +279,21 @@ EvaluateDependency ( } 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); @@ -286,154 +302,191 @@ EvaluateDependency ( 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[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. @@ -444,7 +497,8 @@ EFIAPI ValidateDependency ( IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, IN UINTN MaxDepexSize, - OUT UINT32 *DepexSize + OUT UINT32 *DepexSize, + OUT UINT32 *LastAttemptStatus OPTIONAL ) { UINT8 *Depex; @@ -493,16 +547,23 @@ ValidateDependency ( } } + 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[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 @@ -512,7 +573,8 @@ EFIAPI GetImageDependency ( IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, IN UINTN ImageSize, - OUT UINT32 *DepexSize + OUT UINT32 *DepexSize, + OUT UINT32 *LastAttemptStatus OPTIONAL ) { EFI_FIRMWARE_IMAGE_DEP *Depex; @@ -530,6 +592,9 @@ GetImageDependency ( // // Pointer overflow. Invalid image. // + if (LastAttemptStatus != NULL) { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GET_DEPEX_FAILURE; + } return NULL; } @@ -539,7 +604,7 @@ GetImageDependency ( // // Validate the dependency and get the size of dependency // - if (ValidateDependency (Depex, MaxDepexSize, DepexSize)) { + if (ValidateDependency (Depex, MaxDepexSize, DepexSize, LastAttemptStatus)) { return Depex; } diff --git a/FmpDevicePkg/Test/UnitTest/Library/FmpDependencyLib/EvaluateDependencyUnitTest.c b/FmpDevicePkg/Test/UnitTest/Library/FmpDependencyLib/EvaluateDependencyUnitTest.c index f8ccdd906f..01ac19a7d5 100644 --- a/FmpDevicePkg/Test/UnitTest/Library/FmpDependencyLib/EvaluateDependencyUnitTest.c +++ b/FmpDevicePkg/Test/UnitTest/Library/FmpDependencyLib/EvaluateDependencyUnitTest.c @@ -2,6 +2,7 @@ Unit tests of EvaluateDependency API in FmpDependencyLib. Copyright (c) 2020, Intel Corporation. All rights reserved.
+ Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -162,6 +163,7 @@ EvaluateDependencyTest ( { BASIC_TEST_CONTEXT *TestContext; BOOLEAN EvaluationResult; + UINT32 LastAttemptStatus; TestContext = (BASIC_TEST_CONTEXT *)Context; @@ -169,8 +171,9 @@ EvaluateDependencyTest ( (EFI_FIRMWARE_IMAGE_DEP *)TestContext->Dependencies, TestContext->DependenciesSize, mFmpVersions, - sizeof(mFmpVersions)/sizeof(FMP_DEPEX_CHECK_VERSION_DATA) - ); + sizeof(mFmpVersions)/sizeof(FMP_DEPEX_CHECK_VERSION_DATA), + &LastAttemptStatus + ); UT_ASSERT_EQUAL (EvaluationResult, TestContext->ExpectedResult);