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