From nobody Sat Feb 7 07:10:07 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+59623+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+59623+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1589507498; cv=none; d=zohomail.com; s=zohoarc; b=GJBYZ+237R1768Abs87L6cMz+Z4/JIjKF8mTJPvVbGTct27vtaR48GbReA9jCmmoGqs6e8wAyyY3/dOWKGTZFPiucwjf5bV8TPY/uebkYJItAJgSzfuGb8MY5u3rYHpEi66barYOXNYuv8hkUQgn/ajbqBvnyeVpoAJexBZSXBE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1589507498; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=3NSP3+VLpnUBzDGkFr+4xp7gXQq3FOiEFgsVITlLyqo=; b=U9aBDlPSbEG1BtsBbu+7phyG8xuFQmpfjUa0YOgOPorSY6wBTGPTgtLrgU4CINbiQocJf5kz4tN0XhRX1NtTl0kGL0nq2XuDw0O6GOdAzZXDhAcXd7Or9dL1nvDYO7SYYZSuQxXMv8j4tVkaFX+e3bCI5DhRg08pYQZdNVSrY+o= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+59623+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1589507498611900.839199519979; Thu, 14 May 2020 18:51:38 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id wEq8YY1788612xudeYJXFcKn; Thu, 14 May 2020 18:51:37 -0700 X-Received: from mga07.intel.com (mga07.intel.com []) by mx.groups.io with SMTP id smtpd.web12.5790.1589507494847076587 for ; Thu, 14 May 2020 18:51:37 -0700 IronPort-SDR: PKdqg/YhB2Cy8zCcgcCH51nYh/XCq7RJDOafP+L+iWYbC/TyfB6jmiJY1p0EtciZMDhpIqBlNN 8Hx0G46+vTSg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 May 2020 18:51:36 -0700 IronPort-SDR: Yci2BYjPlVUfoUK6KDznuXxZwIm6PTN0Gt5n/X5MQC346BkEoLfIAFDRyWQjoe5u6Il9wsGtOX fwMM3mWMPDWA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,393,1583222400"; d="scan'208";a="263038430" X-Received: from shwdeopenpsi174.ccr.corp.intel.com ([10.239.157.39]) by orsmga003.jf.intel.com with ESMTP; 14 May 2020 18:51:35 -0700 From: "Xu, Wei6" To: devel@edk2.groups.io Cc: Michael D Kinney , Liming Gao , Sean Brogan Subject: [edk2-devel] [PATCH V4 1/5] FmpDevicePkg: Add FmpDependency library class and BASE instance Date: Fri, 15 May 2020 09:51:19 +0800 Message-Id: <20200515015123.11484-2-wei6.xu@intel.com> In-Reply-To: <20200515015123.11484-1-wei6.xu@intel.com> References: <20200515015123.11484-1-wei6.xu@intel.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,wei6.xu@intel.com X-Gm-Message-State: ngXe99oQS88qPrEdVPMgEkWrx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1589507497; bh=wjwCmufQsCeyFQPQvaplEyDVPFWvbfuHN5sRid0JkZI=; h=Cc:Date:From:Reply-To:Subject:To; b=sjBh0gRmbISt8YclKrlY+u6H+1FJ8lJ6/n2TnZ/QOOaoe/PLmgqa863/2wTLYzpIQwI CsxVA0y0Qf4kQVo0n98CTmVuUf1TuilntqVNNjdY65HnGGhHUssJJYAtAaVAWFxsFwH3q OJJ/RxtMo0plQ5gUUS+gT2mtDsZn32asz24= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2696 This library provides services to evaluate Fmp capsule dependency expression, validate dependency expression and get dependency from firmware image. Cc: Michael D Kinney Cc: Liming Gao Cc: Sean Brogan Signed-off-by: Wei6 Xu Reviewed-by: Sean Brogan --- FmpDevicePkg/FmpDevicePkg.dec | 6 +- FmpDevicePkg/FmpDevicePkg.dsc | 4 +- FmpDevicePkg/Include/Library/FmpDependencyLib.h | 89 ++++ .../Library/FmpDependencyLib/FmpDependencyLib.c | 546 +++++++++++++++++= ++++ .../Library/FmpDependencyLib/FmpDependencyLib.inf | 34 ++ .../Library/FmpDependencyLib/FmpDependencyLib.uni | 12 + 6 files changed, 689 insertions(+), 2 deletions(-) create mode 100644 FmpDevicePkg/Include/Library/FmpDependencyLib.h create mode 100644 FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c create mode 100644 FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.= inf create mode 100644 FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.= uni diff --git a/FmpDevicePkg/FmpDevicePkg.dec b/FmpDevicePkg/FmpDevicePkg.dec index 55671878dd..4947008346 100644 --- a/FmpDevicePkg/FmpDevicePkg.dec +++ b/FmpDevicePkg/FmpDevicePkg.dec @@ -5,11 +5,11 @@ # instance that supports the update of firmware storage devices using UEFI # Capsules. The behavior of the Firmware Management Protocol instance is # customized using libraries and PCDs. # # Copyright (c) 2016, Microsoft Corporation. All rights reserved.
-# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # ## =20 @@ -33,10 +33,14 @@ =20 ## @libraryclass Provides firmware device specific services to support # updates of a firmware image stored in a firmware devi= ce. FmpDeviceLib|Include/Library/FmpDeviceLib.h =20 + ## @libraryclass Provides generic services to support capsule dependen= cy + # expression evaluation. + FmpDependencyLib|Include/Library/FmpDependencyLib.h + [LibraryClasses.Common.Private] ## @libraryclass Provides services to retrieve values from a capsule's= FMP # Payload Header. The structure is not included in the # library class. Instead, services are provided to ret= rieve # information from the FMP Payload Header. If informat= ion is diff --git a/FmpDevicePkg/FmpDevicePkg.dsc b/FmpDevicePkg/FmpDevicePkg.dsc index b8fb9d7c19..dfb3c1a141 100644 --- a/FmpDevicePkg/FmpDevicePkg.dsc +++ b/FmpDevicePkg/FmpDevicePkg.dsc @@ -5,11 +5,11 @@ # instance that supports the update of firmware storage devices using UEFI # Capsules. The behavior of the Firmware Management Protocol instance is # customized using libraries and PCDs. # # Copyright (c) 2016, Microsoft Corporation. All rights reserved.
-# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All right= s reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -58,10 +58,11 @@ !endif FmpAuthenticationLib|SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAu= thenticationLibPkcs7.inf CapsuleUpdatePolicyLib|FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/C= apsuleUpdatePolicyLibNull.inf FmpPayloadHeaderLib|FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloa= dHeaderLibV1.inf FmpDeviceLib|FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf + FmpDependencyLib|FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.= inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplat= e.inf =20 [LibraryClasses.ARM, LibraryClasses.AARCH64] # # It is not possible to prevent the ARM compiler for generic intrinsic f= unctions. @@ -86,10 +87,11 @@ # FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNu= ll.inf FmpDevicePkg/Library/CapsuleUpdatePolicyLibOnProtocol/CapsuleUpdatePolic= yLibOnProtocol.inf FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloadHeaderLibV1.inf FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf + FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf FmpDevicePkg/FmpDxe/FmpDxeLib.inf =20 # # Modules # diff --git a/FmpDevicePkg/Include/Library/FmpDependencyLib.h b/FmpDevicePkg= /Include/Library/FmpDependencyLib.h new file mode 100644 index 0000000000..1110eefa9a --- /dev/null +++ b/FmpDevicePkg/Include/Library/FmpDependencyLib.h @@ -0,0 +1,89 @@ +/** @file + Fmp Capsule Dependency support functions for Firmware Management Protoco= l based + firmware updates. + + Copyright (c) 2020, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __FMP_DEPENDENCY_LIB__ +#define __FMP_DEPENDENCY_LIB__ + +#include +#include + +// +// Data struct to store FMP ImageType and version for dependency check. +// +typedef struct { + EFI_GUID ImageTypeId; + UINT32 Version; +} FMP_DEPEX_CHECK_VERSION_DATA; + +/** + 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. + + @retval TRUE The capsule is valid. + @retval FALSE The capsule is invalid. + +**/ +BOOLEAN +EFIAPI +ValidateDependency ( + IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, + IN UINTN MaxDepexSize, + OUT UINT32 *DepexSize + ); + +/** + 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. + + @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 + ); + +/** + 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 wi= ll + evaluate to FALSE. + + @param[in] Dependencies Dependency expressions. + @param[in] DependenciesSize Size of Dependency expressions. + @param[in] FmpVersions Array of Fmp ImageTypeId and version. Th= is + parameter is optional and can be set to = NULL. + @param[in] FmpVersionsCount Element count of the array. When FmpVers= ions + is NULL, FmpVersionsCount must be 0. + + @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 + ); + +#endif diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c b/Fmp= DevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c new file mode 100644 index 0000000000..91dc0b9abd --- /dev/null +++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c @@ -0,0 +1,546 @@ +/** @file + Supports Fmp Capsule Dependency Expression. + + Copyright (c) 2020, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include + +// +// 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 =3D NULL; +DEPEX_ELEMENT *mDepexEvaluationStackEnd =3D NULL; +DEPEX_ELEMENT *mDepexEvaluationStackPointer =3D 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 =3D DEPEX_STACK_SIZE_INCREMENT; + if (mDepexEvaluationStack !=3D NULL) { + Size =3D Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack); + } + + NewStack =3D AllocatePool (Size * sizeof (DEPEX_ELEMENT)); + if (NewStack =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "GrowDepexStack: Cannot allocate memory for depen= dency evaluation stack!\n")); + return EFI_OUT_OF_RESOURCES; + } + + if (mDepexEvaluationStack !=3D NULL) { + // + // Copy to Old Stack to the New Stack + // + CopyMem ( + NewStack, + mDepexEvaluationStack, + (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (DEPEX_E= LEMENT) + ); + + // + // Free The Old Stack + // + FreePool (mDepexEvaluationStack); + } + + // + // Make the Stack pointer point to the old data in the new stack + // + mDepexEvaluationStackPointer =3D NewStack + (mDepexEvaluationStackPointe= r - mDepexEvaluationStack); + mDepexEvaluationStack =3D NewStack; + mDepexEvaluationStackEnd =3D 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 !=3D BooleanType && Type !=3D VersionType) { + return EFI_INVALID_PARAMETER; + } + + // + // Check for a stack overflow condition + // + if (mDepexEvaluationStackPointer =3D=3D mDepexEvaluationStackEnd) { + // + // Grow the stack + // + Status =3D GrowDepexStack (); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Element.Value.Version =3D Value; + Element.Type =3D Type; + + // + // Push the item onto the stack + // + *mDepexEvaluationStackPointer =3D 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 =3D=3D mDepexEvaluationStack) { + DEBUG ((DEBUG_ERROR, "EvaluateDependency: Stack underflow!\n")); + return EFI_ACCESS_DENIED; + } + + // + // Pop the item off the stack + // + mDepexEvaluationStackPointer--; + *Element =3D *mDepexEvaluationStackPointer; + if ((*Element).Type !=3D Type) { + DEBUG ((DEBUG_ERROR, "EvaluateDependency: Popped element type is misma= tched!\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 wi= ll + evaluate to FALSE. + + @param[in] Dependencies Dependency expressions. + @param[in] DependenciesSize Size of Dependency expressions. + @param[in] FmpVersions Array of Fmp ImageTypeId and version. Th= is + parameter is optional and can be set to = NULL. + @param[in] FmpVersionsCount Element count of the array. When FmpVers= ions + is NULL, FmpVersionsCount must be 0. + + @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 + ) +{ + EFI_STATUS Status; + UINT8 *Iterator; + UINT8 Index; + DEPEX_ELEMENT Element1; + DEPEX_ELEMENT Element2; + GUID ImageTypeId; + UINT32 Version; + + // + // Check if parameter is valid. + // + if (Dependencies =3D=3D NULL || DependenciesSize =3D=3D 0) { + return FALSE; + } + + if (FmpVersions =3D=3D NULL && FmpVersionsCount > 0) { + return FALSE; + } + + // + // Clean out memory leaks in Depex Boolean stack. Leaks are only caused = by + // incorrectly formed DEPEX expressions + // + mDepexEvaluationStackPointer =3D mDepexEvaluationStack; + + Iterator =3D (UINT8 *) Dependencies->Dependencies; + while (Iterator < (UINT8 *) Dependencies->Dependencies + DependenciesSiz= e) { + switch (*Iterator) + { + case EFI_FMP_DEP_PUSH_GUID: + if (Iterator + sizeof (EFI_GUID) >=3D (UINT8 *) Dependencies->Depend= encies + DependenciesSize) { + DEBUG ((DEBUG_ERROR, "EvaluateDependency: GUID extends beyond end = of dependency expression!\n")); + goto Error; + } + + CopyGuid (&ImageTypeId, (EFI_GUID *) (Iterator + 1)); + Iterator =3D Iterator + sizeof (EFI_GUID); + + for (Index =3D 0; Index < FmpVersionsCount; Index ++) { + if(CompareGuid (&FmpVersions[Index].ImageTypeId, &ImageTypeId)){ + Status =3D Push (FmpVersions[Index].Version, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + } + } + if (Index =3D=3D FmpVersionsCount) { + DEBUG ((DEBUG_ERROR, "EvaluateDependency: %g is not found!\n", &Im= ageTypeId)); + goto Error; + } + break; + case EFI_FMP_DEP_PUSH_VERSION: + if (Iterator + sizeof (UINT32) >=3D (UINT8 *) Dependencies->Dependen= cies + DependenciesSize ) { + DEBUG ((DEBUG_ERROR, "EvaluateDependency: VERSION extends beyond e= nd of dependency expression!\n")); + goto Error; + } + + Version =3D *(UINT32 *) (Iterator + 1); + Status =3D Push (Version, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Iterator =3D Iterator + sizeof (UINT32); + break; + case EFI_FMP_DEP_VERSION_STR: + Iterator +=3D AsciiStrnLenS ((CHAR8 *) Iterator, DependenciesSize - = (Iterator - Dependencies->Dependencies)); + if (Iterator =3D=3D (UINT8 *) Dependencies->Dependencies + Dependenc= iesSize) { + DEBUG ((DEBUG_ERROR, "EvaluateDependency: STRING extends beyond en= d of dependency expression!\n")); + } + break; + case EFI_FMP_DEP_AND: + Status =3D Pop (&Element1, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Pop (&Element2, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Push (Element1.Value.Boolean & Element2.Value.Boolean, Bo= oleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_OR: + Status =3D Pop (&Element1, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Pop(&Element2, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Push (Element1.Value.Boolean | Element2.Value.Boolean, Bo= oleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_NOT: + Status =3D Pop (&Element1, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Push (!(Element1.Value.Boolean), BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_TRUE: + Status =3D Push (TRUE, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_FALSE: + Status =3D Push (FALSE, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_EQ: + Status =3D Pop (&Element1, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Pop (&Element2, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D (Element1.Value.Version =3D=3D Element2.Value.Version) ? = Push (TRUE, BooleanType) : Push (FALSE, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_GT: + Status =3D Pop (&Element1, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Pop (&Element2, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D (Element1.Value.Version > Element2.Value.Version) ? Push= (TRUE, BooleanType) : Push (FALSE, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_GTE: + Status =3D Pop (&Element1, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Pop (&Element2, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D (Element1.Value.Version >=3D Element2.Value.Version) ? Pu= sh (TRUE, BooleanType) : Push (FALSE, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_LT: + Status =3D Pop (&Element1, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Pop (&Element2, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D (Element1.Value.Version < Element2.Value.Version) ? Push= (TRUE, BooleanType) : Push (FALSE, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_LTE: + Status =3D Pop (&Element1, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D Pop (&Element2, VersionType); + if (EFI_ERROR (Status)) { + goto Error; + } + Status =3D (Element1.Value.Version <=3D Element2.Value.Version) ? Pu= sh (TRUE, BooleanType) : Push (FALSE, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + break; + case EFI_FMP_DEP_END: + Status =3D Pop (&Element1, BooleanType); + if (EFI_ERROR (Status)) { + goto Error; + } + return Element1.Value.Boolean; + default: + DEBUG ((DEBUG_ERROR, "EvaluateDependency: Unknown Opcode - %02x!\n",= *Iterator)); + goto Error; + } + Iterator++; + } + + DEBUG ((DEBUG_ERROR, "EvaluateDependency: No EFI_FMP_DEP_END Opcode in e= xression!\n")); + +Error: + 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. + + @retval TRUE The capsule is valid. + @retval FALSE The capsule is invalid. + +**/ +BOOLEAN +EFIAPI +ValidateDependency ( + IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, + IN UINTN MaxDepexSize, + OUT UINT32 *DepexSize + ) +{ + UINT8 *Depex; + + if (DepexSize !=3D NULL) { + *DepexSize =3D 0; + } + + if (Dependencies =3D=3D NULL) { + return FALSE; + } + + Depex =3D Dependencies->Dependencies; + while (Depex < Dependencies->Dependencies + MaxDepexSize) { + switch (*Depex) + { + case EFI_FMP_DEP_PUSH_GUID: + Depex +=3D sizeof (EFI_GUID) + 1; + break; + case EFI_FMP_DEP_PUSH_VERSION: + Depex +=3D sizeof (UINT32) + 1; + break; + case EFI_FMP_DEP_VERSION_STR: + Depex +=3D AsciiStrnLenS ((CHAR8 *) Depex, Dependencies->Dependencie= s + 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 +=3D 1; + break; + case EFI_FMP_DEP_END: + Depex +=3D 1; + if (DepexSize !=3D NULL) { + *DepexSize =3D (UINT32)(Depex - Dependencies->Dependencies); + } + return TRUE; + default: + return FALSE; + } + } + + 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. + + @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 + ) +{ + EFI_FIRMWARE_IMAGE_DEP *Depex; + UINTN MaxDepexSize; + + if (Image =3D=3D 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) >=3D (UINTN)Image + ImageSize) { + // + // Pointer overflow. Invalid image. + // + return NULL; + } + + Depex =3D (EFI_FIRMWARE_IMAGE_DEP*)((UINT8 *)Image + sizeof (Image->Mono= tonicCount) + Image->AuthInfo.Hdr.dwLength); + MaxDepexSize =3D ImageSize - (sizeof (Image->MonotonicCount) + Image->Au= thInfo.Hdr.dwLength); + + // + // Validate the dependency and get the size of dependency + // + if (ValidateDependency (Depex, MaxDepexSize, DepexSize)) { + return Depex; + } + + return NULL; +} + diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf b/F= mpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf new file mode 100644 index 0000000000..b7e5c8d002 --- /dev/null +++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf @@ -0,0 +1,34 @@ +## @file +# Provides Fmp Capsule Dependency Expression support. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D FmpDependencyLib + MODULE_UNI_FILE =3D FmpDependencyLib.uni + FILE_GUID =3D 67F55EA4-B4CF-4A08-931B-0BBCF1E0F7A3 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D FmpDependencyLib + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 ARM AARCH64 +# + +[Sources] + FmpDependencyLib.c + +[Packages] + MdePkg/MdePkg.dec + FmpDevicePkg/FmpDevicePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni b/F= mpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni new file mode 100644 index 0000000000..422a96b570 --- /dev/null +++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni @@ -0,0 +1,12 @@ +// /** @file +// Provides Fmp Capsule Dependency Expression support. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "FMP Dependency Lib" + +#string STR_MODULE_DESCRIPTION #language en-US "Provides Fmp Capsule Dep= endency Expression support." --=20 2.16.2.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#59623): https://edk2.groups.io/g/devel/message/59623 Mute This Topic: https://groups.io/mt/74219539/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-