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