2 Supports Fmp Capsule Dependency Expression.
4 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/FmpDependencyLib.h>
14 #include <Library/MemoryAllocationLib.h>
17 // Define the initial size of the dependency expression evaluation stack
19 #define DEPEX_STACK_SIZE_INCREMENT 0x1000
22 // Type of stack element
30 // Value of stack element
38 // Stack element used to evaluate dependency expressions
46 // Global stack used to evaluate dependency expressions
48 DEPEX_ELEMENT
*mDepexEvaluationStack
= NULL
;
49 DEPEX_ELEMENT
*mDepexEvaluationStackEnd
= NULL
;
50 DEPEX_ELEMENT
*mDepexEvaluationStackPointer
= NULL
;
53 Grow size of the Depex stack
55 @retval EFI_SUCCESS Stack successfully growed.
56 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
64 DEPEX_ELEMENT
*NewStack
;
67 Size
= DEPEX_STACK_SIZE_INCREMENT
;
68 if (mDepexEvaluationStack
!= NULL
) {
69 Size
= Size
+ (mDepexEvaluationStackEnd
- mDepexEvaluationStack
);
72 NewStack
= AllocatePool (Size
* sizeof (DEPEX_ELEMENT
));
73 if (NewStack
== NULL
) {
74 DEBUG ((DEBUG_ERROR
, "GrowDepexStack: Cannot allocate memory for dependency evaluation stack!\n"));
75 return EFI_OUT_OF_RESOURCES
;
78 if (mDepexEvaluationStack
!= NULL
) {
80 // Copy to Old Stack to the New Stack
84 mDepexEvaluationStack
,
85 (mDepexEvaluationStackEnd
- mDepexEvaluationStack
) * sizeof (DEPEX_ELEMENT
)
91 FreePool (mDepexEvaluationStack
);
95 // Make the Stack pointer point to the old data in the new stack
97 mDepexEvaluationStackPointer
= NewStack
+ (mDepexEvaluationStackPointer
- mDepexEvaluationStack
);
98 mDepexEvaluationStack
= NewStack
;
99 mDepexEvaluationStackEnd
= NewStack
+ Size
;
105 Push an element onto the Stack.
107 @param[in] Value Value to push.
108 @param[in] Type Element Type
110 @retval EFI_SUCCESS The value was pushed onto the stack.
111 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
112 @retval EFI_INVALID_PARAMETER Wrong stack element type.
122 DEPEX_ELEMENT Element
;
127 if (Type
!= BooleanType
&& Type
!= VersionType
) {
128 return EFI_INVALID_PARAMETER
;
132 // Check for a stack overflow condition
134 if (mDepexEvaluationStackPointer
== mDepexEvaluationStackEnd
) {
138 Status
= GrowDepexStack ();
139 if (EFI_ERROR (Status
)) {
144 Element
.Value
.Version
= Value
;
148 // Push the item onto the stack
150 *mDepexEvaluationStackPointer
= Element
;
151 mDepexEvaluationStackPointer
++;
157 Pop an element from the stack.
159 @param[out] Element Element to pop.
160 @param[in] Type Type of element.
162 @retval EFI_SUCCESS The value was popped onto the stack.
163 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
164 @retval EFI_INVALID_PARAMETER Type is mismatched.
169 OUT DEPEX_ELEMENT
*Element
,
174 // Check for a stack underflow condition
176 if (mDepexEvaluationStackPointer
== mDepexEvaluationStack
) {
177 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: Stack underflow!\n"));
178 return EFI_ACCESS_DENIED
;
182 // Pop the item off the stack
184 mDepexEvaluationStackPointer
--;
185 *Element
= *mDepexEvaluationStackPointer
;
186 if ((*Element
).Type
!= Type
) {
187 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: Popped element type is mismatched!\n"));
188 return EFI_INVALID_PARAMETER
;
194 Evaluate the dependencies. The caller must search all the Fmp instances and
195 gather their versions into FmpVersions parameter. If there is PUSH_GUID opcode
196 in dependency expression with no FmpVersions provided, the dependency will
199 @param[in] Dependencies Dependency expressions.
200 @param[in] DependenciesSize Size of Dependency expressions.
201 @param[in] FmpVersions Array of Fmp ImageTypeId and version. This
202 parameter is optional and can be set to NULL.
203 @param[in] FmpVersionsCount Element count of the array. When FmpVersions
204 is NULL, FmpVersionsCount must be 0.
206 @retval TRUE Dependency expressions evaluate to TRUE.
207 @retval FALSE Dependency expressions evaluate to FALSE.
213 IN EFI_FIRMWARE_IMAGE_DEP
*Dependencies
,
214 IN UINTN DependenciesSize
,
215 IN FMP_DEPEX_CHECK_VERSION_DATA
*FmpVersions OPTIONAL
,
216 IN UINTN FmpVersionsCount
222 DEPEX_ELEMENT Element1
;
223 DEPEX_ELEMENT Element2
;
228 // Check if parameter is valid.
230 if (Dependencies
== NULL
|| DependenciesSize
== 0) {
234 if (FmpVersions
== NULL
&& FmpVersionsCount
> 0) {
239 // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
240 // incorrectly formed DEPEX expressions
242 mDepexEvaluationStackPointer
= mDepexEvaluationStack
;
244 Iterator
= (UINT8
*) Dependencies
->Dependencies
;
245 while (Iterator
< (UINT8
*) Dependencies
->Dependencies
+ DependenciesSize
) {
248 case EFI_FMP_DEP_PUSH_GUID
:
249 if (Iterator
+ sizeof (EFI_GUID
) >= (UINT8
*) Dependencies
->Dependencies
+ DependenciesSize
) {
250 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: GUID extends beyond end of dependency expression!\n"));
254 CopyGuid (&ImageTypeId
, (EFI_GUID
*) (Iterator
+ 1));
255 Iterator
= Iterator
+ sizeof (EFI_GUID
);
257 for (Index
= 0; Index
< FmpVersionsCount
; Index
++) {
258 if(CompareGuid (&FmpVersions
[Index
].ImageTypeId
, &ImageTypeId
)){
259 Status
= Push (FmpVersions
[Index
].Version
, VersionType
);
260 if (EFI_ERROR (Status
)) {
266 if (Index
== FmpVersionsCount
) {
267 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: %g is not found!\n", &ImageTypeId
));
271 case EFI_FMP_DEP_PUSH_VERSION
:
272 if (Iterator
+ sizeof (UINT32
) >= (UINT8
*) Dependencies
->Dependencies
+ DependenciesSize
) {
273 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: VERSION extends beyond end of dependency expression!\n"));
277 Version
= *(UINT32
*) (Iterator
+ 1);
278 Status
= Push (Version
, VersionType
);
279 if (EFI_ERROR (Status
)) {
282 Iterator
= Iterator
+ sizeof (UINT32
);
284 case EFI_FMP_DEP_VERSION_STR
:
285 Iterator
+= AsciiStrnLenS ((CHAR8
*) Iterator
, DependenciesSize
- (Iterator
- Dependencies
->Dependencies
));
286 if (Iterator
== (UINT8
*) Dependencies
->Dependencies
+ DependenciesSize
) {
287 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: STRING extends beyond end of dependency expression!\n"));
290 case EFI_FMP_DEP_AND
:
291 Status
= Pop (&Element1
, BooleanType
);
292 if (EFI_ERROR (Status
)) {
295 Status
= Pop (&Element2
, BooleanType
);
296 if (EFI_ERROR (Status
)) {
299 Status
= Push (Element1
.Value
.Boolean
& Element2
.Value
.Boolean
, BooleanType
);
300 if (EFI_ERROR (Status
)) {
305 Status
= Pop (&Element1
, BooleanType
);
306 if (EFI_ERROR (Status
)) {
309 Status
= Pop(&Element2
, BooleanType
);
310 if (EFI_ERROR (Status
)) {
313 Status
= Push (Element1
.Value
.Boolean
| Element2
.Value
.Boolean
, BooleanType
);
314 if (EFI_ERROR (Status
)) {
318 case EFI_FMP_DEP_NOT
:
319 Status
= Pop (&Element1
, BooleanType
);
320 if (EFI_ERROR (Status
)) {
323 Status
= Push (!(Element1
.Value
.Boolean
), BooleanType
);
324 if (EFI_ERROR (Status
)) {
328 case EFI_FMP_DEP_TRUE
:
329 Status
= Push (TRUE
, BooleanType
);
330 if (EFI_ERROR (Status
)) {
334 case EFI_FMP_DEP_FALSE
:
335 Status
= Push (FALSE
, BooleanType
);
336 if (EFI_ERROR (Status
)) {
341 Status
= Pop (&Element1
, VersionType
);
342 if (EFI_ERROR (Status
)) {
345 Status
= Pop (&Element2
, VersionType
);
346 if (EFI_ERROR (Status
)) {
349 Status
= (Element1
.Value
.Version
== Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
350 if (EFI_ERROR (Status
)) {
355 Status
= Pop (&Element1
, VersionType
);
356 if (EFI_ERROR (Status
)) {
359 Status
= Pop (&Element2
, VersionType
);
360 if (EFI_ERROR (Status
)) {
363 Status
= (Element1
.Value
.Version
> Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
364 if (EFI_ERROR (Status
)) {
368 case EFI_FMP_DEP_GTE
:
369 Status
= Pop (&Element1
, VersionType
);
370 if (EFI_ERROR (Status
)) {
373 Status
= Pop (&Element2
, VersionType
);
374 if (EFI_ERROR (Status
)) {
377 Status
= (Element1
.Value
.Version
>= Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
378 if (EFI_ERROR (Status
)) {
383 Status
= Pop (&Element1
, VersionType
);
384 if (EFI_ERROR (Status
)) {
387 Status
= Pop (&Element2
, VersionType
);
388 if (EFI_ERROR (Status
)) {
391 Status
= (Element1
.Value
.Version
< Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
392 if (EFI_ERROR (Status
)) {
396 case EFI_FMP_DEP_LTE
:
397 Status
= Pop (&Element1
, VersionType
);
398 if (EFI_ERROR (Status
)) {
401 Status
= Pop (&Element2
, VersionType
);
402 if (EFI_ERROR (Status
)) {
405 Status
= (Element1
.Value
.Version
<= Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
406 if (EFI_ERROR (Status
)) {
410 case EFI_FMP_DEP_END
:
411 Status
= Pop (&Element1
, BooleanType
);
412 if (EFI_ERROR (Status
)) {
415 return Element1
.Value
.Boolean
;
417 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: Unknown Opcode - %02x!\n", *Iterator
));
423 DEBUG ((DEBUG_ERROR
, "EvaluateDependency: No EFI_FMP_DEP_END Opcode in exression!\n"));
430 Validate the dependency expression and output its size.
432 @param[in] Dependencies Pointer to the EFI_FIRMWARE_IMAGE_DEP.
433 @param[in] MaxDepexSize Max size of the dependency.
434 @param[out] DepexSize Size of dependency.
436 @retval TRUE The capsule is valid.
437 @retval FALSE The capsule is invalid.
443 IN EFI_FIRMWARE_IMAGE_DEP
*Dependencies
,
444 IN UINTN MaxDepexSize
,
445 OUT UINT32
*DepexSize
450 if (DepexSize
!= NULL
) {
454 if (Dependencies
== NULL
) {
458 Depex
= Dependencies
->Dependencies
;
459 while (Depex
< Dependencies
->Dependencies
+ MaxDepexSize
) {
462 case EFI_FMP_DEP_PUSH_GUID
:
463 Depex
+= sizeof (EFI_GUID
) + 1;
465 case EFI_FMP_DEP_PUSH_VERSION
:
466 Depex
+= sizeof (UINT32
) + 1;
468 case EFI_FMP_DEP_VERSION_STR
:
469 Depex
+= AsciiStrnLenS ((CHAR8
*) Depex
, Dependencies
->Dependencies
+ MaxDepexSize
- Depex
) + 1;
471 case EFI_FMP_DEP_AND
:
473 case EFI_FMP_DEP_NOT
:
474 case EFI_FMP_DEP_TRUE
:
475 case EFI_FMP_DEP_FALSE
:
478 case EFI_FMP_DEP_GTE
:
480 case EFI_FMP_DEP_LTE
:
483 case EFI_FMP_DEP_END
:
485 if (DepexSize
!= NULL
) {
486 *DepexSize
= (UINT32
)(Depex
- Dependencies
->Dependencies
);
498 Get dependency from firmware image.
500 @param[in] Image Points to the firmware image.
501 @param[in] ImageSize Size, in bytes, of the firmware image.
502 @param[out] DepexSize Size, in bytes, of the dependency.
504 @retval The pointer to dependency.
508 EFI_FIRMWARE_IMAGE_DEP
*
511 IN EFI_FIRMWARE_IMAGE_AUTHENTICATION
*Image
,
513 OUT UINT32
*DepexSize
516 EFI_FIRMWARE_IMAGE_DEP
*Depex
;
524 // Check to make sure that operation can be safely performed.
526 if (((UINTN
)Image
+ sizeof (Image
->MonotonicCount
) + Image
->AuthInfo
.Hdr
.dwLength
) < (UINTN
)Image
|| \
527 ((UINTN
)Image
+ sizeof (Image
->MonotonicCount
) + Image
->AuthInfo
.Hdr
.dwLength
) >= (UINTN
)Image
+ ImageSize
) {
529 // Pointer overflow. Invalid image.
534 Depex
= (EFI_FIRMWARE_IMAGE_DEP
*)((UINT8
*)Image
+ sizeof (Image
->MonotonicCount
) + Image
->AuthInfo
.Hdr
.dwLength
);
535 MaxDepexSize
= ImageSize
- (sizeof (Image
->MonotonicCount
) + Image
->AuthInfo
.Hdr
.dwLength
);
538 // Validate the dependency and get the size of dependency
540 if (ValidateDependency (Depex
, MaxDepexSize
, DepexSize
)) {