FvReportPei.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /** @file
  2. This driver verifies and reports OBB FVs.
  3. Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "FvReportPei.h"
  7. STATIC CONST HASH_ALG_INFO mHashAlgInfo[] = {
  8. {TPM_ALG_SHA256, SHA256_DIGEST_SIZE, Sha256Init, Sha256Update, Sha256Final, Sha256HashAll}, // 000B
  9. {TPM_ALG_SHA384, SHA384_DIGEST_SIZE, Sha384Init, Sha384Update, Sha384Final, Sha384HashAll}, // 000C
  10. {TPM_ALG_SHA512, SHA512_DIGEST_SIZE, Sha512Init, Sha512Update, Sha512Final, Sha512HashAll}, // 000D
  11. };
  12. /**
  13. Find hash algorithm information from mHashAlgInfo according to given ID.
  14. @param[in] HashAlgId Hash algorithm type id.
  15. @retval Pointer to HASH_ALG_INFO if given hash algorithm is supported.
  16. @retval NULL if given algorithm is not supported.
  17. **/
  18. STATIC
  19. CONST
  20. HASH_ALG_INFO *
  21. FindHashAlgInfo (
  22. IN UINT16 HashAlgId
  23. )
  24. {
  25. UINTN Index;
  26. for (Index = 0; Index < ARRAY_SIZE (mHashAlgInfo); ++Index) {
  27. if (mHashAlgInfo[Index].HashAlgId == HashAlgId) {
  28. return &mHashAlgInfo[Index];
  29. }
  30. }
  31. return NULL;
  32. }
  33. /**
  34. Install a EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI instance so that
  35. TCG driver may use to extend PCRs.
  36. @param[in] FvBuffer Buffer containing the whole FV.
  37. @param[in] FvLength Length of the FV.
  38. @param[in] HashAlgoId Hash algorithm type id.
  39. @param[in] HashSize Hash size.
  40. @param[in] HashValue Hash value buffer.
  41. **/
  42. STATIC
  43. VOID
  44. InstallPreHashFvPpi (
  45. IN VOID *FvBuffer,
  46. IN UINTN FvLength,
  47. IN UINT16 HashAlgoId,
  48. IN UINT16 HashSize,
  49. IN UINT8 *HashValue
  50. )
  51. {
  52. EFI_STATUS Status;
  53. EFI_PEI_PPI_DESCRIPTOR *FvInfoPpiDescriptor;
  54. EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI *PreHashedFvPpi;
  55. UINTN PpiSize;
  56. HASH_INFO *HashInfo;
  57. PpiSize = sizeof (EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI)
  58. + sizeof (sizeof (HASH_INFO))
  59. + HashSize;
  60. PreHashedFvPpi = AllocatePool (PpiSize);
  61. ASSERT (PreHashedFvPpi != NULL);
  62. PreHashedFvPpi->FvBase = (UINT32)(UINTN)FvBuffer;
  63. PreHashedFvPpi->FvLength = (UINT32)FvLength;
  64. PreHashedFvPpi->Count = 1;
  65. HashInfo = HASH_INFO_PTR (PreHashedFvPpi);
  66. HashInfo->HashAlgoId = HashAlgoId;
  67. HashInfo->HashSize = HashSize;
  68. CopyMem (HASH_VALUE_PTR (HashInfo), HashValue, HashSize);
  69. FvInfoPpiDescriptor = AllocatePool (sizeof (EFI_PEI_PPI_DESCRIPTOR));
  70. ASSERT (FvInfoPpiDescriptor != NULL);
  71. FvInfoPpiDescriptor->Guid = &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid;
  72. FvInfoPpiDescriptor->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
  73. FvInfoPpiDescriptor->Ppi = (VOID *) PreHashedFvPpi;
  74. Status = PeiServicesInstallPpi (FvInfoPpiDescriptor);
  75. ASSERT_EFI_ERROR (Status);
  76. }
  77. /**
  78. Calculate and verify hash value for given FV.
  79. @param[in] HashInfo Hash information of the FV.
  80. @param[in] FvInfo Information of FV used for verification.
  81. @param[in] FvNumber Length of the FV.
  82. @param[in] BootMode Length of the FV.
  83. @retval EFI_SUCCESS The given FV is integrate.
  84. @retval EFI_VOLUME_CORRUPTED The given FV is corrupted (hash mismatch).
  85. @retval EFI_UNSUPPORTED The hash algorithm is not supported.
  86. **/
  87. STATIC
  88. EFI_STATUS
  89. VerifyHashedFv (
  90. IN FV_HASH_INFO *HashInfo,
  91. IN HASHED_FV_INFO *FvInfo,
  92. IN UINTN FvNumber,
  93. IN EFI_BOOT_MODE BootMode
  94. )
  95. {
  96. UINTN FvIndex;
  97. CONST HASH_ALG_INFO *AlgInfo;
  98. UINT8 *HashValue;
  99. UINT8 *FvHashValue;
  100. VOID *FvBuffer;
  101. EFI_STATUS Status;
  102. if (HashInfo == NULL ||
  103. HashInfo->HashSize == 0 ||
  104. HashInfo->HashAlgoId == TPM_ALG_NULL) {
  105. DEBUG ((DEBUG_INFO, "Bypass FV hash verification\r\n"));
  106. return EFI_SUCCESS;
  107. }
  108. AlgInfo = FindHashAlgInfo (HashInfo->HashAlgoId);
  109. if (AlgInfo == NULL || AlgInfo->HashSize != HashInfo->HashSize) {
  110. DEBUG ((DEBUG_ERROR, "Unsupported or wrong hash algorithm: %04X (size=%d)\r\n",
  111. HashInfo->HashAlgoId, HashInfo->HashSize));
  112. return EFI_UNSUPPORTED;
  113. }
  114. ASSERT (FvInfo != NULL);
  115. ASSERT (FvNumber > 0);
  116. //
  117. // We need a hash value for each FV as well as one for all FVs.
  118. //
  119. HashValue = AllocateZeroPool (AlgInfo->HashSize * (FvNumber + 1));
  120. ASSERT (HashValue != NULL);
  121. //
  122. // Calculate hash value for each FV first.
  123. //
  124. FvHashValue = HashValue;
  125. for (FvIndex = 0; FvIndex < FvNumber; ++FvIndex) {
  126. //
  127. // FV must be meant for verified boot and/or measured boot.
  128. //
  129. ASSERT ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_VERIFIED_BOOT) != 0 ||
  130. (FvInfo[FvIndex].Flag & HASHED_FV_FLAG_MEASURED_BOOT) != 0);
  131. //
  132. // Skip any FV not meant for current boot mode.
  133. //
  134. if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode)) != 0) {
  135. DEBUG ((DEBUG_INFO, "Skip FV[%016lX] for boot mode[%d]\r\n",
  136. FvInfo[FvIndex].Base, BootMode));
  137. continue;
  138. }
  139. DEBUG ((
  140. DEBUG_INFO,
  141. "Pre-hashed[alg=%04X,size=%d,flag=%016lX] FV: 0x%016lX (%08lX) (Flag=%016lX)\r\n",
  142. HashInfo->HashAlgoId,
  143. HashInfo->HashSize,
  144. HashInfo->HashFlag,
  145. FvInfo[FvIndex].Base,
  146. FvInfo[FvIndex].Length,
  147. FvInfo[FvIndex].Flag
  148. ));
  149. //
  150. // Copy FV to permanent memory to avoid potential TOC/TOU.
  151. //
  152. FvBuffer = AllocatePages (EFI_SIZE_TO_PAGES((UINTN)FvInfo[FvIndex].Length));
  153. ASSERT (FvBuffer != NULL);
  154. CopyMem (FvBuffer, (CONST VOID *)(UINTN)FvInfo[FvIndex].Base, (UINTN)FvInfo[FvIndex].Length);
  155. if (!AlgInfo->HashAll (FvBuffer, (UINTN)FvInfo[FvIndex].Length, FvHashValue)) {
  156. Status = EFI_ABORTED;
  157. goto Done;
  158. }
  159. //
  160. // Report the FV measurement.
  161. //
  162. if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_MEASURED_BOOT) != 0) {
  163. InstallPreHashFvPpi (
  164. FvBuffer,
  165. (UINTN)FvInfo[FvIndex].Length,
  166. HashInfo->HashAlgoId,
  167. HashInfo->HashSize,
  168. FvHashValue
  169. );
  170. }
  171. //
  172. // Don't keep the hash value of current FV if we don't need to verify it.
  173. //
  174. if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_VERIFIED_BOOT) != 0) {
  175. FvHashValue += AlgInfo->HashSize;
  176. }
  177. //
  178. // Use memory copy of the FV from now on.
  179. //
  180. FvInfo[FvIndex].Base = (UINT64)(UINTN)FvBuffer;
  181. }
  182. //
  183. // Check final hash for all FVs.
  184. //
  185. if (FvHashValue == HashValue ||
  186. (AlgInfo->HashAll (HashValue, FvHashValue - HashValue, FvHashValue) &&
  187. CompareMem (HashInfo->Hash, FvHashValue, AlgInfo->HashSize) == 0)) {
  188. Status = EFI_SUCCESS;
  189. } else {
  190. Status = EFI_VOLUME_CORRUPTED;
  191. }
  192. Done:
  193. FreePool (HashValue);
  194. return Status;
  195. }
  196. /**
  197. Report FV to PEI and/or DXE core for dispatch.
  198. @param[in] FvInfo Information of a FV.
  199. **/
  200. STATIC
  201. VOID
  202. ReportHashedFv (
  203. IN HASHED_FV_INFO *FvInfo
  204. )
  205. {
  206. CONST EFI_GUID *FvFormat;
  207. if ((FvInfo->Flag & HASHED_FV_FLAG_REPORT_FV_HOB) != 0) {
  208. //
  209. // Require DXE core to process this FV.
  210. //
  211. BuildFvHob (
  212. (EFI_PHYSICAL_ADDRESS)FvInfo->Base,
  213. FvInfo->Length
  214. );
  215. DEBUG ((DEBUG_INFO, "Reported FV HOB: %016lX (%08lX)\r\n", FvInfo->Base, FvInfo->Length));
  216. }
  217. if ((FvInfo->Flag & HASHED_FV_FLAG_REPORT_FV_INFO_PPI) != 0) {
  218. //
  219. // Require PEI core to process this FV.
  220. //
  221. FvFormat = &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvInfo->Base)->FileSystemGuid;
  222. PeiServicesInstallFvInfoPpi (
  223. FvFormat,
  224. (VOID *)(UINTN)FvInfo->Base,
  225. (UINT32)FvInfo->Length,
  226. NULL,
  227. NULL
  228. );
  229. DEBUG ((DEBUG_INFO, "Reported FV PPI: %016lX (%08lX)\r\n", FvInfo->Base, FvInfo->Length));
  230. }
  231. }
  232. /**
  233. Verify and report pre-hashed FVs.
  234. Doing this must be at post-memory to make sure there's enough memory to hold
  235. all FVs to be verified. This is necessary for mitigating TOCTOU issue.
  236. This function will never return if the verification is failed.
  237. @param[in] StoredHashFvPpi Pointer to PPI containing hash information.
  238. @param[in] BootMode Current boot mode.
  239. @retval Pointer to structure containing valid hash information for current boot mode.
  240. @retval NULL if there's no hash associated with current boot mode.
  241. **/
  242. STATIC
  243. FV_HASH_INFO *
  244. GetHashInfo (
  245. IN EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI *StoredHashFvPpi,
  246. IN EFI_BOOT_MODE BootMode
  247. )
  248. {
  249. FV_HASH_INFO *HashInfo;
  250. if ((StoredHashFvPpi->HashInfo.HashFlag & FV_HASH_FLAG_BOOT_MODE (BootMode)) != 0) {
  251. HashInfo = &StoredHashFvPpi->HashInfo;
  252. } else {
  253. HashInfo = NULL;
  254. }
  255. return HashInfo;
  256. }
  257. /**
  258. Verify and report pre-hashed FVs.
  259. Doing this must be at post-memory to make sure there's enough memory to hold
  260. all FVs to be verified. This is necessary for mitigating TOCTOU issue.
  261. This function will never return if the verification is failed.
  262. @param[in] PeiServices General purpose services available to every PEIM.
  263. @param[in] BootMode Current boot mode.
  264. @retval EFI_SUCCESS The function completed successfully.
  265. **/
  266. STATIC
  267. EFI_STATUS
  268. CheckStoredHashFv (
  269. IN CONST EFI_PEI_SERVICES **PeiServices,
  270. IN EFI_BOOT_MODE BootMode
  271. )
  272. {
  273. EFI_STATUS Status;
  274. EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI *StoredHashFvPpi;
  275. FV_HASH_INFO *HashInfo;
  276. UINTN FvIndex;
  277. //
  278. // Check pre-hashed FV list
  279. //
  280. StoredHashFvPpi = NULL;
  281. Status = PeiServicesLocatePpi (
  282. &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid,
  283. 0,
  284. NULL,
  285. (VOID**)&StoredHashFvPpi
  286. );
  287. if (!EFI_ERROR(Status) && StoredHashFvPpi != NULL && StoredHashFvPpi->FvNumber > 0) {
  288. HashInfo = GetHashInfo (StoredHashFvPpi, BootMode);
  289. Status = VerifyHashedFv (HashInfo, StoredHashFvPpi->FvInfo,
  290. StoredHashFvPpi->FvNumber, BootMode);
  291. if (!EFI_ERROR (Status)) {
  292. //
  293. // Report the FVs to PEI core and/or DXE core.
  294. //
  295. for (FvIndex = 0; FvIndex < StoredHashFvPpi->FvNumber; ++FvIndex) {
  296. if ((StoredHashFvPpi->FvInfo[FvIndex].Flag
  297. & HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode)) == 0) {
  298. ReportHashedFv (&StoredHashFvPpi->FvInfo[FvIndex]);
  299. }
  300. }
  301. REPORT_STATUS_CODE (
  302. EFI_PROGRESS_CODE,
  303. PcdGet32 (PcdStatusCodeFvVerificationPass)
  304. );
  305. } else {
  306. DEBUG ((DEBUG_ERROR, "ERROR: Failed to verify OBB FVs (%r)\r\n", Status));
  307. REPORT_STATUS_CODE_EX (
  308. EFI_PROGRESS_CODE,
  309. PcdGet32 (PcdStatusCodeFvVerificationFail),
  310. 0,
  311. NULL,
  312. &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid,
  313. StoredHashFvPpi,
  314. sizeof (*StoredHashFvPpi)
  315. );
  316. ASSERT_EFI_ERROR (Status);
  317. }
  318. } else {
  319. DEBUG ((DEBUG_ERROR, "ERROR: No/invalid StoredHashFvPpi located\r\n"));
  320. ASSERT_EFI_ERROR (Status);
  321. ASSERT (StoredHashFvPpi != NULL && StoredHashFvPpi->FvNumber > 0);
  322. Status = EFI_NOT_FOUND;
  323. }
  324. return Status;
  325. }
  326. /**
  327. Main entry for FvReport PEIM.
  328. @param[in] FileHandle Handle of the file being invoked.
  329. @param[in] PeiServices Pointer to PEI Services table.
  330. @retval EFI_SUCCESS If all FVs reported by StoredHashFvPpi are verified.
  331. **/
  332. EFI_STATUS
  333. EFIAPI
  334. FvReportEntryPoint (
  335. IN EFI_PEI_FILE_HANDLE FileHandle,
  336. IN CONST EFI_PEI_SERVICES **PeiServices
  337. )
  338. {
  339. EFI_STATUS Status;
  340. EFI_BOOT_MODE BootMode;
  341. Status = PeiServicesGetBootMode (&BootMode);
  342. ASSERT_EFI_ERROR (Status);
  343. Status = CheckStoredHashFv (PeiServices, BootMode);
  344. if (EFI_ERROR (Status)) {
  345. //
  346. // Never pass control to left part of BIOS if any error.
  347. //
  348. CpuDeadLoop ();
  349. }
  350. return Status;
  351. }