]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/FvReportPei/FvReportPei.c
SecurityPkg: Fix spelling errors
[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
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
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
29 IN UINT16 HashAlgId\r
30 )\r
31{\r
32 UINTN Index;\r
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
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
61 )\r
62{\r
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
68\r
69 PpiSize = sizeof (EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI)\r
70 + sizeof (sizeof (HASH_INFO))\r
71 + HashSize;\r
72\r
73 PreHashedFvPpi = AllocatePool (PpiSize);\r
74 ASSERT (PreHashedFvPpi != NULL);\r
75\r
76 PreHashedFvPpi->FvBase = (UINT32)(UINTN)FvBuffer;\r
77 PreHashedFvPpi->FvLength = (UINT32)FvLength;\r
78 PreHashedFvPpi->Count = 1;\r
79\r
80 HashInfo = HASH_INFO_PTR (PreHashedFvPpi);\r
81 HashInfo->HashAlgoId = HashAlgoId;\r
82 HashInfo->HashSize = HashSize;\r
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
90 FvInfoPpiDescriptor->Ppi = (VOID *) PreHashedFvPpi;\r
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
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
115 )\r
116{\r
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 DEBUG ((DEBUG_INFO, "Bypass FV hash verification\r\n"));\r
128 return EFI_SUCCESS;\r
129 }\r
130\r
131 AlgInfo = FindHashAlgInfo (HashInfo->HashAlgoId);\r
132 if (AlgInfo == NULL || AlgInfo->HashSize != HashInfo->HashSize) {\r
133 DEBUG ((DEBUG_ERROR, "Unsupported or wrong hash algorithm: %04X (size=%d)\r\n",\r
134 HashInfo->HashAlgoId, HashInfo->HashSize));\r
135 return EFI_UNSUPPORTED;\r
136 }\r
137\r
138 ASSERT (FvInfo != NULL);\r
139 ASSERT (FvNumber > 0);\r
140\r
141 //\r
142 // We need a hash value for each FV as well as one for all FVs.\r
143 //\r
144 HashValue = AllocateZeroPool (AlgInfo->HashSize * (FvNumber + 1));\r
145 ASSERT (HashValue != NULL);\r
146\r
147 //\r
d6b926e7 148 // Calculate hash value for each FV first.\r
3743e71a
JW
149 //\r
150 FvHashValue = HashValue;\r
151 for (FvIndex = 0; FvIndex < FvNumber; ++FvIndex) {\r
152 //\r
153 // FV must be meant for verified boot and/or measured boot.\r
154 //\r
155 ASSERT ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_VERIFIED_BOOT) != 0 ||\r
156 (FvInfo[FvIndex].Flag & HASHED_FV_FLAG_MEASURED_BOOT) != 0);\r
157\r
158 //\r
159 // Skip any FV not meant for current boot mode.\r
160 //\r
161 if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode)) != 0) {\r
162 DEBUG ((DEBUG_INFO, "Skip FV[%016lX] for boot mode[%d]\r\n",\r
163 FvInfo[FvIndex].Base, BootMode));\r
164 continue;\r
165 }\r
166\r
167 DEBUG ((\r
168 DEBUG_INFO,\r
169 "Pre-hashed[alg=%04X,size=%d,flag=%016lX] FV: 0x%016lX (%08lX) (Flag=%016lX)\r\n",\r
170 HashInfo->HashAlgoId,\r
171 HashInfo->HashSize,\r
172 HashInfo->HashFlag,\r
173 FvInfo[FvIndex].Base,\r
174 FvInfo[FvIndex].Length,\r
175 FvInfo[FvIndex].Flag\r
176 ));\r
177\r
178 //\r
179 // Copy FV to permanent memory to avoid potential TOC/TOU.\r
180 //\r
181 FvBuffer = AllocatePages (EFI_SIZE_TO_PAGES((UINTN)FvInfo[FvIndex].Length));\r
182 ASSERT (FvBuffer != NULL);\r
183 CopyMem (FvBuffer, (CONST VOID *)(UINTN)FvInfo[FvIndex].Base, (UINTN)FvInfo[FvIndex].Length);\r
184\r
185 if (!AlgInfo->HashAll (FvBuffer, (UINTN)FvInfo[FvIndex].Length, FvHashValue)) {\r
186 Status = EFI_ABORTED;\r
187 goto Done;\r
188 }\r
189\r
190 //\r
191 // Report the FV measurement.\r
192 //\r
193 if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_MEASURED_BOOT) != 0) {\r
194 InstallPreHashFvPpi (\r
195 FvBuffer,\r
196 (UINTN)FvInfo[FvIndex].Length,\r
197 HashInfo->HashAlgoId,\r
198 HashInfo->HashSize,\r
199 FvHashValue\r
200 );\r
201 }\r
202\r
203 //\r
204 // Don't keep the hash value of current FV if we don't need to verify it.\r
205 //\r
206 if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_VERIFIED_BOOT) != 0) {\r
207 FvHashValue += AlgInfo->HashSize;\r
208 }\r
209\r
210 //\r
211 // Use memory copy of the FV from now on.\r
212 //\r
213 FvInfo[FvIndex].Base = (UINT64)(UINTN)FvBuffer;\r
214 }\r
215\r
216 //\r
217 // Check final hash for all FVs.\r
218 //\r
219 if (FvHashValue == HashValue ||\r
220 (AlgInfo->HashAll (HashValue, FvHashValue - HashValue, FvHashValue) &&\r
221 CompareMem (HashInfo->Hash, FvHashValue, AlgInfo->HashSize) == 0)) {\r
222 Status = EFI_SUCCESS;\r
223 } else {\r
224 Status = EFI_VOLUME_CORRUPTED;\r
225 }\r
226\r
227Done:\r
228 FreePool (HashValue);\r
229 return Status;\r
230}\r
231\r
232/**\r
233 Report FV to PEI and/or DXE core for dispatch.\r
234\r
235 @param[in] FvInfo Information of a FV.\r
236\r
237**/\r
238STATIC\r
239VOID\r
240ReportHashedFv (\r
241 IN HASHED_FV_INFO *FvInfo\r
242 )\r
243{\r
244 CONST EFI_GUID *FvFormat;\r
245\r
246 if ((FvInfo->Flag & HASHED_FV_FLAG_REPORT_FV_HOB) != 0) {\r
247 //\r
248 // Require DXE core to process this FV.\r
249 //\r
250 BuildFvHob (\r
251 (EFI_PHYSICAL_ADDRESS)FvInfo->Base,\r
252 FvInfo->Length\r
253 );\r
254 DEBUG ((DEBUG_INFO, "Reported FV HOB: %016lX (%08lX)\r\n", FvInfo->Base, FvInfo->Length));\r
255 }\r
256\r
257 if ((FvInfo->Flag & HASHED_FV_FLAG_REPORT_FV_INFO_PPI) != 0) {\r
258 //\r
259 // Require PEI core to process this FV.\r
260 //\r
261 FvFormat = &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvInfo->Base)->FileSystemGuid;\r
262 PeiServicesInstallFvInfoPpi (\r
263 FvFormat,\r
264 (VOID *)(UINTN)FvInfo->Base,\r
265 (UINT32)FvInfo->Length,\r
266 NULL,\r
267 NULL\r
268 );\r
269 DEBUG ((DEBUG_INFO, "Reported FV PPI: %016lX (%08lX)\r\n", FvInfo->Base, FvInfo->Length));\r
270 }\r
271}\r
272\r
273/**\r
274 Verify and report pre-hashed FVs.\r
275\r
276 Doing this must be at post-memory to make sure there's enough memory to hold\r
277 all FVs to be verified. This is necessary for mitigating TOCTOU issue.\r
278\r
279 This function will never return if the verification is failed.\r
280\r
281 @param[in] StoredHashFvPpi Pointer to PPI containing hash information.\r
282 @param[in] BootMode Current boot mode.\r
283\r
d6b926e7 284 @retval Pointer to structure containing valid hash information for current boot mode.\r
3743e71a
JW
285 @retval NULL if there's no hash associated with current boot mode.\r
286**/\r
287STATIC\r
288FV_HASH_INFO *\r
289GetHashInfo (\r
290 IN EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI *StoredHashFvPpi,\r
291 IN EFI_BOOT_MODE BootMode\r
292 )\r
293{\r
294 FV_HASH_INFO *HashInfo;\r
295\r
296 if ((StoredHashFvPpi->HashInfo.HashFlag & FV_HASH_FLAG_BOOT_MODE (BootMode)) != 0) {\r
297 HashInfo = &StoredHashFvPpi->HashInfo;\r
298 } else {\r
299 HashInfo = NULL;\r
300 }\r
301\r
302 return HashInfo;\r
303}\r
304\r
305/**\r
306 Verify and report pre-hashed FVs.\r
307\r
308 Doing this must be at post-memory to make sure there's enough memory to hold\r
309 all FVs to be verified. This is necessary for mitigating TOCTOU issue.\r
310\r
311 This function will never return if the verification is failed.\r
312\r
313 @param[in] PeiServices General purpose services available to every PEIM.\r
314 @param[in] BootMode Current boot mode.\r
315\r
316 @retval EFI_SUCCESS The function completed successfully.\r
317**/\r
318STATIC\r
319EFI_STATUS\r
320CheckStoredHashFv (\r
321 IN CONST EFI_PEI_SERVICES **PeiServices,\r
322 IN EFI_BOOT_MODE BootMode\r
323 )\r
324{\r
325 EFI_STATUS Status;\r
326 EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI *StoredHashFvPpi;\r
327 FV_HASH_INFO *HashInfo;\r
328 UINTN FvIndex;\r
329\r
330 //\r
331 // Check pre-hashed FV list\r
332 //\r
333 StoredHashFvPpi = NULL;\r
334 Status = PeiServicesLocatePpi (\r
335 &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid,\r
336 0,\r
337 NULL,\r
338 (VOID**)&StoredHashFvPpi\r
339 );\r
340 if (!EFI_ERROR(Status) && StoredHashFvPpi != NULL && StoredHashFvPpi->FvNumber > 0) {\r
341\r
342 HashInfo = GetHashInfo (StoredHashFvPpi, BootMode);\r
343 Status = VerifyHashedFv (HashInfo, StoredHashFvPpi->FvInfo,\r
344 StoredHashFvPpi->FvNumber, BootMode);\r
345 if (!EFI_ERROR (Status)) {\r
346\r
347 //\r
348 // Report the FVs to PEI core and/or DXE core.\r
349 //\r
350 for (FvIndex = 0; FvIndex < StoredHashFvPpi->FvNumber; ++FvIndex) {\r
351 if ((StoredHashFvPpi->FvInfo[FvIndex].Flag\r
352 & HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode)) == 0) {\r
353 ReportHashedFv (&StoredHashFvPpi->FvInfo[FvIndex]);\r
354 }\r
355 }\r
356\r
357 REPORT_STATUS_CODE (\r
358 EFI_PROGRESS_CODE,\r
359 PcdGet32 (PcdStatusCodeFvVerificationPass)\r
360 );\r
361\r
362 } else {\r
363\r
364 DEBUG ((DEBUG_ERROR, "ERROR: Failed to verify OBB FVs (%r)\r\n", Status));\r
365\r
366 REPORT_STATUS_CODE_EX (\r
367 EFI_PROGRESS_CODE,\r
368 PcdGet32 (PcdStatusCodeFvVerificationFail),\r
369 0,\r
370 NULL,\r
371 &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid,\r
372 StoredHashFvPpi,\r
373 sizeof (*StoredHashFvPpi)\r
374 );\r
375\r
376 ASSERT_EFI_ERROR (Status);\r
377\r
378 }\r
379\r
380 } else {\r
381\r
382 DEBUG ((DEBUG_ERROR, "ERROR: No/invalid StoredHashFvPpi located\r\n"));\r
383\r
384 ASSERT_EFI_ERROR (Status);\r
385 ASSERT (StoredHashFvPpi != NULL && StoredHashFvPpi->FvNumber > 0);\r
386\r
387 Status = EFI_NOT_FOUND;\r
388 }\r
389\r
390 return Status;\r
391}\r
392\r
393/**\r
394 Main entry for FvReport PEIM.\r
395\r
396 @param[in] FileHandle Handle of the file being invoked.\r
397 @param[in] PeiServices Pointer to PEI Services table.\r
398\r
399 @retval EFI_SUCCESS If all FVs reported by StoredHashFvPpi are verified.\r
400\r
401**/\r
402EFI_STATUS\r
403EFIAPI\r
404FvReportEntryPoint (\r
405 IN EFI_PEI_FILE_HANDLE FileHandle,\r
406 IN CONST EFI_PEI_SERVICES **PeiServices\r
407 )\r
408{\r
409 EFI_STATUS Status;\r
410 EFI_BOOT_MODE BootMode;\r
411\r
412 Status = PeiServicesGetBootMode (&BootMode);\r
413 ASSERT_EFI_ERROR (Status);\r
414\r
415 Status = CheckStoredHashFv (PeiServices, BootMode);\r
416 if (EFI_ERROR (Status)) {\r
417 //\r
418 // Never pass control to left part of BIOS if any error.\r
419 //\r
420 CpuDeadLoop ();\r
421 }\r
422\r
423 return Status;\r
424}\r