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