FmpDependencyLib.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. /** @file
  2. Supports Fmp Capsule Dependency Expression.
  3. Copyright (c) Microsoft Corporation.<BR>
  4. Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <PiDxe.h>
  8. #include <Library/BaseLib.h>
  9. #include <Library/BaseMemoryLib.h>
  10. #include <Library/DebugLib.h>
  11. #include <Library/FmpDependencyLib.h>
  12. #include <Library/MemoryAllocationLib.h>
  13. #include <Guid/SystemResourceTable.h>
  14. #include <LastAttemptStatus.h>
  15. #include <FmpLastAttemptStatus.h>
  16. //
  17. // Define the initial size of the dependency expression evaluation stack
  18. //
  19. #define DEPEX_STACK_SIZE_INCREMENT 0x1000
  20. //
  21. // Type of stack element
  22. //
  23. typedef enum {
  24. BooleanType,
  25. VersionType
  26. } ELEMENT_TYPE;
  27. //
  28. // Value of stack element
  29. //
  30. typedef union {
  31. BOOLEAN Boolean;
  32. UINT32 Version;
  33. } ELEMENT_VALUE;
  34. //
  35. // Stack element used to evaluate dependency expressions
  36. //
  37. typedef struct {
  38. ELEMENT_VALUE Value;
  39. ELEMENT_TYPE Type;
  40. } DEPEX_ELEMENT;
  41. //
  42. // Global stack used to evaluate dependency expressions
  43. //
  44. DEPEX_ELEMENT *mDepexEvaluationStack = NULL;
  45. DEPEX_ELEMENT *mDepexEvaluationStackEnd = NULL;
  46. DEPEX_ELEMENT *mDepexEvaluationStackPointer = NULL;
  47. /**
  48. Grow size of the Depex stack
  49. @retval EFI_SUCCESS Stack successfully growed.
  50. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
  51. **/
  52. EFI_STATUS
  53. GrowDepexStack (
  54. VOID
  55. )
  56. {
  57. DEPEX_ELEMENT *NewStack;
  58. UINTN Size;
  59. Size = DEPEX_STACK_SIZE_INCREMENT;
  60. if (mDepexEvaluationStack != NULL) {
  61. Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
  62. }
  63. NewStack = AllocatePool (Size * sizeof (DEPEX_ELEMENT));
  64. if (NewStack == NULL) {
  65. DEBUG ((DEBUG_ERROR, "GrowDepexStack: Cannot allocate memory for dependency evaluation stack!\n"));
  66. return EFI_OUT_OF_RESOURCES;
  67. }
  68. if (mDepexEvaluationStack != NULL) {
  69. //
  70. // Copy to Old Stack to the New Stack
  71. //
  72. CopyMem (
  73. NewStack,
  74. mDepexEvaluationStack,
  75. (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (DEPEX_ELEMENT)
  76. );
  77. //
  78. // Free The Old Stack
  79. //
  80. FreePool (mDepexEvaluationStack);
  81. }
  82. //
  83. // Make the Stack pointer point to the old data in the new stack
  84. //
  85. mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
  86. mDepexEvaluationStack = NewStack;
  87. mDepexEvaluationStackEnd = NewStack + Size;
  88. return EFI_SUCCESS;
  89. }
  90. /**
  91. Push an element onto the Stack.
  92. @param[in] Value Value to push.
  93. @param[in] Type Element Type
  94. @retval EFI_SUCCESS The value was pushed onto the stack.
  95. @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
  96. @retval EFI_INVALID_PARAMETER Wrong stack element type.
  97. **/
  98. EFI_STATUS
  99. Push (
  100. IN UINT32 Value,
  101. IN UINTN Type
  102. )
  103. {
  104. EFI_STATUS Status;
  105. DEPEX_ELEMENT Element;
  106. //
  107. // Check Type
  108. //
  109. if ((Type != BooleanType) && (Type != VersionType)) {
  110. return EFI_INVALID_PARAMETER;
  111. }
  112. //
  113. // Check for a stack overflow condition
  114. //
  115. if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
  116. //
  117. // Grow the stack
  118. //
  119. Status = GrowDepexStack ();
  120. if (EFI_ERROR (Status)) {
  121. return Status;
  122. }
  123. }
  124. Element.Value.Version = Value;
  125. Element.Type = Type;
  126. //
  127. // Push the item onto the stack
  128. //
  129. *mDepexEvaluationStackPointer = Element;
  130. mDepexEvaluationStackPointer++;
  131. return EFI_SUCCESS;
  132. }
  133. /**
  134. Pop an element from the stack.
  135. @param[out] Element Element to pop.
  136. @param[in] Type Type of element.
  137. @retval EFI_SUCCESS The value was popped onto the stack.
  138. @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
  139. @retval EFI_INVALID_PARAMETER Type is mismatched.
  140. **/
  141. EFI_STATUS
  142. Pop (
  143. OUT DEPEX_ELEMENT *Element,
  144. IN ELEMENT_TYPE Type
  145. )
  146. {
  147. //
  148. // Check for a stack underflow condition
  149. //
  150. if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
  151. DEBUG ((DEBUG_ERROR, "EvaluateDependency: Stack underflow!\n"));
  152. return EFI_ACCESS_DENIED;
  153. }
  154. //
  155. // Pop the item off the stack
  156. //
  157. mDepexEvaluationStackPointer--;
  158. *Element = *mDepexEvaluationStackPointer;
  159. if ((*Element).Type != Type) {
  160. DEBUG ((DEBUG_ERROR, "EvaluateDependency: Popped element type is mismatched!\n"));
  161. return EFI_INVALID_PARAMETER;
  162. }
  163. return EFI_SUCCESS;
  164. }
  165. /**
  166. Evaluate the dependencies. The caller must search all the Fmp instances and
  167. gather their versions into FmpVersions parameter. If there is PUSH_GUID opcode
  168. in dependency expression with no FmpVersions provided, the dependency will
  169. evaluate to FALSE.
  170. @param[in] Dependencies Dependency expressions.
  171. @param[in] DependenciesSize Size of Dependency expressions.
  172. @param[in] FmpVersions Array of Fmp ImageTypeId and version. This
  173. parameter is optional and can be set to NULL.
  174. @param[in] FmpVersionsCount Element count of the array. When FmpVersions
  175. is NULL, FmpVersionsCount must be 0.
  176. @param[out] LastAttemptStatus An optional pointer to a UINT32 that holds the
  177. last attempt status to report back to the caller.
  178. This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS
  179. if an error code is not set.
  180. @retval TRUE Dependency expressions evaluate to TRUE.
  181. @retval FALSE Dependency expressions evaluate to FALSE.
  182. **/
  183. BOOLEAN
  184. EFIAPI
  185. EvaluateDependency (
  186. IN EFI_FIRMWARE_IMAGE_DEP *Dependencies,
  187. IN UINTN DependenciesSize,
  188. IN FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions OPTIONAL,
  189. IN UINTN FmpVersionsCount,
  190. OUT UINT32 *LastAttemptStatus OPTIONAL
  191. )
  192. {
  193. EFI_STATUS Status;
  194. UINT8 *Iterator;
  195. UINT8 Index;
  196. DEPEX_ELEMENT Element1;
  197. DEPEX_ELEMENT Element2;
  198. GUID ImageTypeId;
  199. UINT32 Version;
  200. UINT32 LocalLastAttemptStatus;
  201. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
  202. //
  203. // Check if parameter is valid.
  204. //
  205. if ((Dependencies == NULL) || (DependenciesSize == 0)) {
  206. return FALSE;
  207. }
  208. if ((FmpVersions == NULL) && (FmpVersionsCount > 0)) {
  209. return FALSE;
  210. }
  211. //
  212. // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
  213. // incorrectly formed DEPEX expressions
  214. //
  215. mDepexEvaluationStackPointer = mDepexEvaluationStack;
  216. Iterator = (UINT8 *)Dependencies->Dependencies;
  217. while (Iterator < (UINT8 *)Dependencies->Dependencies + DependenciesSize) {
  218. switch (*Iterator) {
  219. case EFI_FMP_DEP_PUSH_GUID:
  220. if (Iterator + sizeof (EFI_GUID) >= (UINT8 *)Dependencies->Dependencies + DependenciesSize) {
  221. DEBUG ((DEBUG_ERROR, "EvaluateDependency: GUID extends beyond end of dependency expression!\n"));
  222. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GUID_BEYOND_DEPEX;
  223. goto Error;
  224. }
  225. CopyGuid (&ImageTypeId, (EFI_GUID *)(Iterator + 1));
  226. Iterator = Iterator + sizeof (EFI_GUID);
  227. for (Index = 0; Index < FmpVersionsCount; Index++) {
  228. if (CompareGuid (&FmpVersions[Index].ImageTypeId, &ImageTypeId)) {
  229. Status = Push (FmpVersions[Index].Version, VersionType);
  230. if (EFI_ERROR (Status)) {
  231. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  232. goto Error;
  233. }
  234. break;
  235. }
  236. }
  237. if (Index == FmpVersionsCount) {
  238. DEBUG ((DEBUG_ERROR, "EvaluateDependency: %g is not found!\n", &ImageTypeId));
  239. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_FMP_NOT_FOUND;
  240. goto Error;
  241. }
  242. break;
  243. case EFI_FMP_DEP_PUSH_VERSION:
  244. if (Iterator + sizeof (UINT32) >= (UINT8 *)Dependencies->Dependencies + DependenciesSize ) {
  245. DEBUG ((DEBUG_ERROR, "EvaluateDependency: VERSION extends beyond end of dependency expression!\n"));
  246. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_BEYOND_DEPEX;
  247. goto Error;
  248. }
  249. Version = *(UINT32 *)(Iterator + 1);
  250. Status = Push (Version, VersionType);
  251. if (EFI_ERROR (Status)) {
  252. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  253. goto Error;
  254. }
  255. Iterator = Iterator + sizeof (UINT32);
  256. break;
  257. case EFI_FMP_DEP_VERSION_STR:
  258. Iterator += AsciiStrnLenS ((CHAR8 *)Iterator, DependenciesSize - (Iterator - Dependencies->Dependencies));
  259. if (Iterator == (UINT8 *)Dependencies->Dependencies + DependenciesSize) {
  260. DEBUG ((DEBUG_ERROR, "EvaluateDependency: STRING extends beyond end of dependency expression!\n"));
  261. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_STR_BEYOND_DEPEX;
  262. goto Error;
  263. }
  264. break;
  265. case EFI_FMP_DEP_AND:
  266. Status = Pop (&Element1, BooleanType);
  267. if (EFI_ERROR (Status)) {
  268. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  269. goto Error;
  270. }
  271. Status = Pop (&Element2, BooleanType);
  272. if (EFI_ERROR (Status)) {
  273. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  274. goto Error;
  275. }
  276. Status = Push (Element1.Value.Boolean & Element2.Value.Boolean, BooleanType);
  277. if (EFI_ERROR (Status)) {
  278. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  279. goto Error;
  280. }
  281. break;
  282. case EFI_FMP_DEP_OR:
  283. Status = Pop (&Element1, BooleanType);
  284. if (EFI_ERROR (Status)) {
  285. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  286. goto Error;
  287. }
  288. Status = Pop (&Element2, BooleanType);
  289. if (EFI_ERROR (Status)) {
  290. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  291. goto Error;
  292. }
  293. Status = Push (Element1.Value.Boolean | Element2.Value.Boolean, BooleanType);
  294. if (EFI_ERROR (Status)) {
  295. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  296. goto Error;
  297. }
  298. break;
  299. case EFI_FMP_DEP_NOT:
  300. Status = Pop (&Element1, BooleanType);
  301. if (EFI_ERROR (Status)) {
  302. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  303. goto Error;
  304. }
  305. Status = Push (!(Element1.Value.Boolean), BooleanType);
  306. if (EFI_ERROR (Status)) {
  307. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  308. goto Error;
  309. }
  310. break;
  311. case EFI_FMP_DEP_TRUE:
  312. Status = Push (TRUE, BooleanType);
  313. if (EFI_ERROR (Status)) {
  314. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  315. goto Error;
  316. }
  317. break;
  318. case EFI_FMP_DEP_FALSE:
  319. Status = Push (FALSE, BooleanType);
  320. if (EFI_ERROR (Status)) {
  321. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  322. goto Error;
  323. }
  324. break;
  325. case EFI_FMP_DEP_EQ:
  326. Status = Pop (&Element1, VersionType);
  327. if (EFI_ERROR (Status)) {
  328. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  329. goto Error;
  330. }
  331. Status = Pop (&Element2, VersionType);
  332. if (EFI_ERROR (Status)) {
  333. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  334. goto Error;
  335. }
  336. Status = (Element1.Value.Version == Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
  337. if (EFI_ERROR (Status)) {
  338. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  339. goto Error;
  340. }
  341. break;
  342. case EFI_FMP_DEP_GT:
  343. Status = Pop (&Element1, VersionType);
  344. if (EFI_ERROR (Status)) {
  345. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  346. goto Error;
  347. }
  348. Status = Pop (&Element2, VersionType);
  349. if (EFI_ERROR (Status)) {
  350. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  351. goto Error;
  352. }
  353. Status = (Element1.Value.Version > Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
  354. if (EFI_ERROR (Status)) {
  355. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  356. goto Error;
  357. }
  358. break;
  359. case EFI_FMP_DEP_GTE:
  360. Status = Pop (&Element1, VersionType);
  361. if (EFI_ERROR (Status)) {
  362. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  363. goto Error;
  364. }
  365. Status = Pop (&Element2, VersionType);
  366. if (EFI_ERROR (Status)) {
  367. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  368. goto Error;
  369. }
  370. Status = (Element1.Value.Version >= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
  371. if (EFI_ERROR (Status)) {
  372. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  373. goto Error;
  374. }
  375. break;
  376. case EFI_FMP_DEP_LT:
  377. Status = Pop (&Element1, VersionType);
  378. if (EFI_ERROR (Status)) {
  379. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  380. goto Error;
  381. }
  382. Status = Pop (&Element2, VersionType);
  383. if (EFI_ERROR (Status)) {
  384. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  385. goto Error;
  386. }
  387. Status = (Element1.Value.Version < Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
  388. if (EFI_ERROR (Status)) {
  389. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  390. goto Error;
  391. }
  392. break;
  393. case EFI_FMP_DEP_LTE:
  394. Status = Pop (&Element1, VersionType);
  395. if (EFI_ERROR (Status)) {
  396. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  397. goto Error;
  398. }
  399. Status = Pop (&Element2, VersionType);
  400. if (EFI_ERROR (Status)) {
  401. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  402. goto Error;
  403. }
  404. Status = (Element1.Value.Version <= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
  405. if (EFI_ERROR (Status)) {
  406. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
  407. goto Error;
  408. }
  409. break;
  410. case EFI_FMP_DEP_END:
  411. Status = Pop (&Element1, BooleanType);
  412. if (EFI_ERROR (Status)) {
  413. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
  414. goto Error;
  415. }
  416. return Element1.Value.Boolean;
  417. default:
  418. DEBUG ((DEBUG_ERROR, "EvaluateDependency: Unknown Opcode - %02x!\n", *Iterator));
  419. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_UNKNOWN_OPCODE;
  420. goto Error;
  421. }
  422. Iterator++;
  423. }
  424. DEBUG ((DEBUG_ERROR, "EvaluateDependency: No EFI_FMP_DEP_END Opcode in expression!\n"));
  425. LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE;
  426. Error:
  427. if (LastAttemptStatus != NULL) {
  428. *LastAttemptStatus = LocalLastAttemptStatus;
  429. }
  430. return FALSE;
  431. }
  432. /**
  433. Validate the dependency expression and output its size.
  434. @param[in] Dependencies Pointer to the EFI_FIRMWARE_IMAGE_DEP.
  435. @param[in] MaxDepexSize Max size of the dependency.
  436. @param[out] DepexSize Size of dependency.
  437. @param[out] LastAttemptStatus An optional pointer to a UINT32 that holds the
  438. last attempt status to report back to the caller.
  439. If a last attempt status error code is not returned,
  440. this function will not modify the LastAttemptStatus value.
  441. @retval TRUE The dependency expression is valid.
  442. @retval FALSE The dependency expression is invalid.
  443. **/
  444. BOOLEAN
  445. EFIAPI
  446. ValidateDependency (
  447. IN EFI_FIRMWARE_IMAGE_DEP *Dependencies,
  448. IN UINTN MaxDepexSize,
  449. OUT UINT32 *DepexSize,
  450. OUT UINT32 *LastAttemptStatus OPTIONAL
  451. )
  452. {
  453. UINT8 *Depex;
  454. if (DepexSize != NULL) {
  455. *DepexSize = 0;
  456. }
  457. if (Dependencies == NULL) {
  458. return FALSE;
  459. }
  460. Depex = Dependencies->Dependencies;
  461. while (Depex < Dependencies->Dependencies + MaxDepexSize) {
  462. switch (*Depex) {
  463. case EFI_FMP_DEP_PUSH_GUID:
  464. Depex += sizeof (EFI_GUID) + 1;
  465. break;
  466. case EFI_FMP_DEP_PUSH_VERSION:
  467. Depex += sizeof (UINT32) + 1;
  468. break;
  469. case EFI_FMP_DEP_VERSION_STR:
  470. Depex += AsciiStrnLenS ((CHAR8 *)Depex, Dependencies->Dependencies + MaxDepexSize - Depex) + 1;
  471. break;
  472. case EFI_FMP_DEP_AND:
  473. case EFI_FMP_DEP_OR:
  474. case EFI_FMP_DEP_NOT:
  475. case EFI_FMP_DEP_TRUE:
  476. case EFI_FMP_DEP_FALSE:
  477. case EFI_FMP_DEP_EQ:
  478. case EFI_FMP_DEP_GT:
  479. case EFI_FMP_DEP_GTE:
  480. case EFI_FMP_DEP_LT:
  481. case EFI_FMP_DEP_LTE:
  482. Depex += 1;
  483. break;
  484. case EFI_FMP_DEP_END:
  485. Depex += 1;
  486. if (DepexSize != NULL) {
  487. *DepexSize = (UINT32)(Depex - Dependencies->Dependencies);
  488. }
  489. return TRUE;
  490. default:
  491. return FALSE;
  492. }
  493. }
  494. if (LastAttemptStatus != NULL) {
  495. *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE;
  496. }
  497. return FALSE;
  498. }
  499. /**
  500. Get dependency from firmware image.
  501. @param[in] Image Points to the firmware image.
  502. @param[in] ImageSize Size, in bytes, of the firmware image.
  503. @param[out] DepexSize Size, in bytes, of the dependency.
  504. @param[out] LastAttemptStatus An optional pointer to a UINT32 that holds the
  505. last attempt status to report back to the caller.
  506. If a last attempt status error code is not returned,
  507. this function will not modify the LastAttemptStatus value.
  508. @retval The pointer to dependency.
  509. @retval Null
  510. **/
  511. EFI_FIRMWARE_IMAGE_DEP *
  512. EFIAPI
  513. GetImageDependency (
  514. IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
  515. IN UINTN ImageSize,
  516. OUT UINT32 *DepexSize,
  517. OUT UINT32 *LastAttemptStatus OPTIONAL
  518. )
  519. {
  520. EFI_FIRMWARE_IMAGE_DEP *Depex;
  521. UINTN MaxDepexSize;
  522. if (Image == NULL) {
  523. return NULL;
  524. }
  525. //
  526. // Check to make sure that operation can be safely performed.
  527. //
  528. if ((((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) < (UINTN)Image) || \
  529. (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize))
  530. {
  531. //
  532. // Pointer overflow. Invalid image.
  533. //
  534. if (LastAttemptStatus != NULL) {
  535. *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GET_DEPEX_FAILURE;
  536. }
  537. return NULL;
  538. }
  539. Depex = (EFI_FIRMWARE_IMAGE_DEP *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
  540. MaxDepexSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
  541. //
  542. // Validate the dependency and get the size of dependency
  543. //
  544. if (ValidateDependency (Depex, MaxDepexSize, DepexSize, LastAttemptStatus)) {
  545. return Depex;
  546. }
  547. return NULL;
  548. }