• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   The library instance provides security service of TPM measure boot.
3 
4   Caution: This file requires additional review when modified.
5   This library will have external input - PE/COFF image and GPT partition.
6   This external input must be validated carefully to avoid security issue like
7   buffer overflow, integer overflow.
8 
9   DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
10   read is within the image buffer.
11 
12   TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
13   data structure within this image buffer before use.
14 
15   TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
16   partition data carefully.
17 
18 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
19 This program and the accompanying materials
20 are licensed and made available under the terms and conditions of the BSD License
21 which accompanies this distribution.  The full text of the license may be found at
22 http://opensource.org/licenses/bsd-license.php
23 
24 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
25 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 
27 **/
28 
29 #include <PiDxe.h>
30 
31 #include <Protocol/TcgService.h>
32 #include <Protocol/BlockIo.h>
33 #include <Protocol/DiskIo.h>
34 #include <Protocol/FirmwareVolumeBlock.h>
35 
36 #include <Guid/MeasuredFvHob.h>
37 
38 #include <Library/BaseLib.h>
39 #include <Library/DebugLib.h>
40 #include <Library/BaseMemoryLib.h>
41 #include <Library/MemoryAllocationLib.h>
42 #include <Library/DevicePathLib.h>
43 #include <Library/UefiBootServicesTableLib.h>
44 #include <Library/BaseCryptLib.h>
45 #include <Library/PeCoffLib.h>
46 #include <Library/SecurityManagementLib.h>
47 #include <Library/HobLib.h>
48 
49 //
50 // Flag to check GPT partition. It only need be measured once.
51 //
52 BOOLEAN                           mMeasureGptTableFlag = FALSE;
53 UINTN                             mMeasureGptCount = 0;
54 VOID                              *mFileBuffer;
55 UINTN                             mTpmImageSize;
56 //
57 // Measured FV handle cache
58 //
59 EFI_HANDLE                        mCacheMeasuredHandle  = NULL;
60 MEASURED_HOB_DATA                 *mMeasuredHobData     = NULL;
61 
62 /**
63   Reads contents of a PE/COFF image in memory buffer.
64 
65   Caution: This function may receive untrusted input.
66   PE/COFF image is external input, so this function will make sure the PE/COFF image content
67   read is within the image buffer.
68 
69   @param  FileHandle      Pointer to the file handle to read the PE/COFF image.
70   @param  FileOffset      Offset into the PE/COFF image to begin the read operation.
71   @param  ReadSize        On input, the size in bytes of the requested read operation.
72                           On output, the number of bytes actually read.
73   @param  Buffer          Output buffer that contains the data read from the PE/COFF image.
74 
75   @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size
76 **/
77 EFI_STATUS
78 EFIAPI
DxeTpmMeasureBootLibImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)79 DxeTpmMeasureBootLibImageRead (
80   IN     VOID    *FileHandle,
81   IN     UINTN   FileOffset,
82   IN OUT UINTN   *ReadSize,
83   OUT    VOID    *Buffer
84   )
85 {
86   UINTN               EndPosition;
87 
88   if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
89     return EFI_INVALID_PARAMETER;
90   }
91 
92   if (MAX_ADDRESS - FileOffset < *ReadSize) {
93     return EFI_INVALID_PARAMETER;
94   }
95 
96   EndPosition = FileOffset + *ReadSize;
97   if (EndPosition > mTpmImageSize) {
98     *ReadSize = (UINT32)(mTpmImageSize - FileOffset);
99   }
100 
101   if (FileOffset >= mTpmImageSize) {
102     *ReadSize = 0;
103   }
104 
105   CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
106 
107   return EFI_SUCCESS;
108 }
109 
110 /**
111   Measure GPT table data into TPM log.
112 
113   Caution: This function may receive untrusted input.
114   The GPT partition table is external input, so this function should parse partition data carefully.
115 
116   @param TcgProtocol             Pointer to the located TCG protocol instance.
117   @param GptHandle               Handle that GPT partition was installed.
118 
119   @retval EFI_SUCCESS            Successfully measure GPT table.
120   @retval EFI_UNSUPPORTED        Not support GPT table on the given handle.
121   @retval EFI_DEVICE_ERROR       Can't get GPT table because device error.
122   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure GPT table.
123   @retval other error value
124 **/
125 EFI_STATUS
126 EFIAPI
TcgMeasureGptTable(IN EFI_TCG_PROTOCOL * TcgProtocol,IN EFI_HANDLE GptHandle)127 TcgMeasureGptTable (
128   IN  EFI_TCG_PROTOCOL   *TcgProtocol,
129   IN  EFI_HANDLE         GptHandle
130   )
131 {
132   EFI_STATUS                        Status;
133   EFI_BLOCK_IO_PROTOCOL             *BlockIo;
134   EFI_DISK_IO_PROTOCOL              *DiskIo;
135   EFI_PARTITION_TABLE_HEADER        *PrimaryHeader;
136   EFI_PARTITION_ENTRY               *PartitionEntry;
137   UINT8                             *EntryPtr;
138   UINTN                             NumberOfPartition;
139   UINT32                            Index;
140   TCG_PCR_EVENT                     *TcgEvent;
141   EFI_GPT_DATA                      *GptData;
142   UINT32                            EventSize;
143   UINT32                            EventNumber;
144   EFI_PHYSICAL_ADDRESS              EventLogLastEntry;
145 
146   if (mMeasureGptCount > 0) {
147     return EFI_SUCCESS;
148   }
149 
150   Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo);
151   if (EFI_ERROR (Status)) {
152     return EFI_UNSUPPORTED;
153   }
154   Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo);
155   if (EFI_ERROR (Status)) {
156     return EFI_UNSUPPORTED;
157   }
158   //
159   // Read the EFI Partition Table Header
160   //
161   PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize);
162   if (PrimaryHeader == NULL) {
163     return EFI_OUT_OF_RESOURCES;
164   }
165   Status = DiskIo->ReadDisk (
166                      DiskIo,
167                      BlockIo->Media->MediaId,
168                      1 * BlockIo->Media->BlockSize,
169                      BlockIo->Media->BlockSize,
170                      (UINT8 *)PrimaryHeader
171                      );
172   if (EFI_ERROR (Status)) {
173     DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n"));
174     FreePool (PrimaryHeader);
175     return EFI_DEVICE_ERROR;
176   }
177   //
178   // Read the partition entry.
179   //
180   EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
181   if (EntryPtr == NULL) {
182     FreePool (PrimaryHeader);
183     return EFI_OUT_OF_RESOURCES;
184   }
185   Status = DiskIo->ReadDisk (
186                      DiskIo,
187                      BlockIo->Media->MediaId,
188                      MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
189                      PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
190                      EntryPtr
191                      );
192   if (EFI_ERROR (Status)) {
193     FreePool (PrimaryHeader);
194     FreePool (EntryPtr);
195     return EFI_DEVICE_ERROR;
196   }
197 
198   //
199   // Count the valid partition
200   //
201   PartitionEntry    = (EFI_PARTITION_ENTRY *)EntryPtr;
202   NumberOfPartition = 0;
203   for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
204     if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
205       NumberOfPartition++;
206     }
207     PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
208   }
209 
210   //
211   // Prepare Data for Measurement
212   //
213   EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
214                         + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
215   TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));
216   if (TcgEvent == NULL) {
217     FreePool (PrimaryHeader);
218     FreePool (EntryPtr);
219     return EFI_OUT_OF_RESOURCES;
220   }
221 
222   TcgEvent->PCRIndex   = 5;
223   TcgEvent->EventType  = EV_EFI_GPT_EVENT;
224   TcgEvent->EventSize  = EventSize;
225   GptData = (EFI_GPT_DATA *) TcgEvent->Event;
226 
227   //
228   // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
229   //
230   CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
231   GptData->NumberOfPartitions = NumberOfPartition;
232   //
233   // Copy the valid partition entry
234   //
235   PartitionEntry    = (EFI_PARTITION_ENTRY*)EntryPtr;
236   NumberOfPartition = 0;
237   for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
238     if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
239       CopyMem (
240         (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,
241         (UINT8 *)PartitionEntry,
242         PrimaryHeader->SizeOfPartitionEntry
243         );
244       NumberOfPartition++;
245     }
246     PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
247   }
248 
249   //
250   // Measure the GPT data
251   //
252   EventNumber = 1;
253   Status = TcgProtocol->HashLogExtendEvent (
254              TcgProtocol,
255              (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,
256              (UINT64) TcgEvent->EventSize,
257              TPM_ALG_SHA,
258              TcgEvent,
259              &EventNumber,
260              &EventLogLastEntry
261              );
262   if (!EFI_ERROR (Status)) {
263     mMeasureGptCount++;
264   }
265 
266   FreePool (PrimaryHeader);
267   FreePool (EntryPtr);
268   FreePool (TcgEvent);
269 
270   return Status;
271 }
272 
273 /**
274   Measure PE image into TPM log based on the authenticode image hashing in
275   PE/COFF Specification 8.0 Appendix A.
276 
277   Caution: This function may receive untrusted input.
278   PE/COFF image is external input, so this function will validate its data structure
279   within this image buffer before use.
280 
281   Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
282   its caller function DxeTpmMeasureBootHandler().
283 
284   @param[in] TcgProtocol    Pointer to the located TCG protocol instance.
285   @param[in] ImageAddress   Start address of image buffer.
286   @param[in] ImageSize      Image size
287   @param[in] LinkTimeBase   Address that the image is loaded into memory.
288   @param[in] ImageType      Image subsystem type.
289   @param[in] FilePath       File path is corresponding to the input image.
290 
291   @retval EFI_SUCCESS            Successfully measure image.
292   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.
293   @retval EFI_UNSUPPORTED        ImageType is unsupported or PE image is mal-format.
294   @retval other error value
295 
296 **/
297 EFI_STATUS
298 EFIAPI
TcgMeasurePeImage(IN EFI_TCG_PROTOCOL * TcgProtocol,IN EFI_PHYSICAL_ADDRESS ImageAddress,IN UINTN ImageSize,IN UINTN LinkTimeBase,IN UINT16 ImageType,IN EFI_DEVICE_PATH_PROTOCOL * FilePath)299 TcgMeasurePeImage (
300   IN  EFI_TCG_PROTOCOL          *TcgProtocol,
301   IN  EFI_PHYSICAL_ADDRESS      ImageAddress,
302   IN  UINTN                     ImageSize,
303   IN  UINTN                     LinkTimeBase,
304   IN  UINT16                    ImageType,
305   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath
306   )
307 {
308   EFI_STATUS                           Status;
309   TCG_PCR_EVENT                        *TcgEvent;
310   EFI_IMAGE_LOAD_EVENT                 *ImageLoad;
311   UINT32                               FilePathSize;
312   VOID                                 *Sha1Ctx;
313   UINTN                                CtxSize;
314   EFI_IMAGE_DOS_HEADER                 *DosHdr;
315   UINT32                               PeCoffHeaderOffset;
316   EFI_IMAGE_SECTION_HEADER             *Section;
317   UINT8                                *HashBase;
318   UINTN                                HashSize;
319   UINTN                                SumOfBytesHashed;
320   EFI_IMAGE_SECTION_HEADER             *SectionHeader;
321   UINTN                                Index;
322   UINTN                                Pos;
323   UINT16                               Magic;
324   UINT32                               EventSize;
325   UINT32                               EventNumber;
326   EFI_PHYSICAL_ADDRESS                 EventLogLastEntry;
327   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
328   UINT32                               NumberOfRvaAndSizes;
329   BOOLEAN                              HashStatus;
330   UINT32                               CertSize;
331 
332   Status        = EFI_UNSUPPORTED;
333   ImageLoad     = NULL;
334   SectionHeader = NULL;
335   Sha1Ctx       = NULL;
336   FilePathSize  = (UINT32) GetDevicePathSize (FilePath);
337 
338   //
339   // Determine destination PCR by BootPolicy
340   //
341   EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
342   TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));
343   if (TcgEvent == NULL) {
344     return EFI_OUT_OF_RESOURCES;
345   }
346 
347   TcgEvent->EventSize = EventSize;
348   ImageLoad           = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event;
349 
350   switch (ImageType) {
351     case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
352       TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;
353       TcgEvent->PCRIndex  = 4;
354       break;
355     case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
356       TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;
357       TcgEvent->PCRIndex  = 2;
358       break;
359     case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
360       TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;
361       TcgEvent->PCRIndex  = 2;
362       break;
363     default:
364       DEBUG ((
365         EFI_D_ERROR,
366         "TcgMeasurePeImage: Unknown subsystem type %d",
367         ImageType
368         ));
369       goto Finish;
370   }
371 
372   ImageLoad->ImageLocationInMemory = ImageAddress;
373   ImageLoad->ImageLengthInMemory   = ImageSize;
374   ImageLoad->ImageLinkTimeAddress  = LinkTimeBase;
375   ImageLoad->LengthOfDevicePath    = FilePathSize;
376   if ((FilePath != NULL) && (FilePathSize != 0)) {
377     CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);
378   }
379 
380   //
381   // Check PE/COFF image
382   //
383   DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
384   PeCoffHeaderOffset = 0;
385   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
386     PeCoffHeaderOffset = DosHdr->e_lfanew;
387   }
388 
389   Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
390   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
391     goto Finish;
392   }
393 
394   //
395   // PE/COFF Image Measurement
396   //
397   //    NOTE: The following codes/steps are based upon the authenticode image hashing in
398   //      PE/COFF Specification 8.0 Appendix A.
399   //
400   //
401 
402   // 1.  Load the image header into memory.
403 
404   // 2.  Initialize a SHA hash context.
405   CtxSize = Sha1GetContextSize ();
406   Sha1Ctx = AllocatePool (CtxSize);
407   if (Sha1Ctx == NULL) {
408     Status = EFI_OUT_OF_RESOURCES;
409     goto Finish;
410   }
411 
412   HashStatus = Sha1Init (Sha1Ctx);
413   if (!HashStatus) {
414     goto Finish;
415   }
416 
417   //
418   // Measuring PE/COFF Image Header;
419   // But CheckSum field and SECURITY data directory (certificate) are excluded
420   //
421   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
422     //
423     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
424     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
425     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
426     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
427     //
428     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
429   } else {
430     //
431     // Get the magic value from the PE/COFF Optional Header
432     //
433     Magic = Hdr.Pe32->OptionalHeader.Magic;
434   }
435 
436   //
437   // 3.  Calculate the distance from the base of the image header to the image checksum address.
438   // 4.  Hash the image header from its base to beginning of the image checksum.
439   //
440   HashBase = (UINT8 *) (UINTN) ImageAddress;
441   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
442     //
443     // Use PE32 offset
444     //
445     NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
446     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
447   } else {
448     //
449     // Use PE32+ offset
450     //
451     NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
452     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
453   }
454 
455   HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
456   if (!HashStatus) {
457     goto Finish;
458   }
459 
460   //
461   // 5.  Skip over the image checksum (it occupies a single ULONG).
462   //
463   if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
464     //
465     // 6.  Since there is no Cert Directory in optional header, hash everything
466     //     from the end of the checksum to the end of image header.
467     //
468     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
469       //
470       // Use PE32 offset.
471       //
472       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
473       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
474     } else {
475       //
476       // Use PE32+ offset.
477       //
478       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
479       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
480     }
481 
482     if (HashSize != 0) {
483       HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);
484       if (!HashStatus) {
485         goto Finish;
486       }
487     }
488   } else {
489     //
490     // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
491     //
492     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
493       //
494       // Use PE32 offset
495       //
496       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
497       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
498     } else {
499       //
500       // Use PE32+ offset
501       //
502       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
503       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
504     }
505 
506     if (HashSize != 0) {
507       HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);
508       if (!HashStatus) {
509         goto Finish;
510       }
511     }
512 
513     //
514     // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
515     // 9.  Hash everything from the end of the Cert Directory to the end of image header.
516     //
517     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
518       //
519       // Use PE32 offset
520       //
521       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
522       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
523     } else {
524       //
525       // Use PE32+ offset
526       //
527       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
528       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
529     }
530 
531     if (HashSize != 0) {
532       HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);
533       if (!HashStatus) {
534         goto Finish;
535       }
536     }
537   }
538 
539   //
540   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
541   //
542   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
543     //
544     // Use PE32 offset
545     //
546     SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
547   } else {
548     //
549     // Use PE32+ offset
550     //
551     SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
552   }
553 
554   //
555   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
556   //     structures in the image. The 'NumberOfSections' field of the image
557   //     header indicates how big the table should be. Do not include any
558   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
559   //
560   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
561   if (SectionHeader == NULL) {
562     Status = EFI_OUT_OF_RESOURCES;
563     goto Finish;
564   }
565 
566   //
567   // 12.  Using the 'PointerToRawData' in the referenced section headers as
568   //      a key, arrange the elements in the table in ascending order. In other
569   //      words, sort the section headers according to the disk-file offset of
570   //      the section.
571   //
572   Section = (EFI_IMAGE_SECTION_HEADER *) (
573                (UINT8 *) (UINTN) ImageAddress +
574                PeCoffHeaderOffset +
575                sizeof(UINT32) +
576                sizeof(EFI_IMAGE_FILE_HEADER) +
577                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
578                );
579   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
580     Pos = Index;
581     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
582       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
583       Pos--;
584     }
585     CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
586     Section += 1;
587   }
588 
589   //
590   // 13.  Walk through the sorted table, bring the corresponding section
591   //      into memory, and hash the entire section (using the 'SizeOfRawData'
592   //      field in the section header to determine the amount of data to hash).
593   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
594   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
595   //
596   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
597     Section  = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
598     if (Section->SizeOfRawData == 0) {
599       continue;
600     }
601     HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
602     HashSize = (UINTN) Section->SizeOfRawData;
603 
604     HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
605     if (!HashStatus) {
606       goto Finish;
607     }
608 
609     SumOfBytesHashed += HashSize;
610   }
611 
612   //
613   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
614   //      data in the file that needs to be added to the hash. This data begins
615   //      at file offset SUM_OF_BYTES_HASHED and its length is:
616   //             FileSize  -  (CertDirectory->Size)
617   //
618   if (ImageSize > SumOfBytesHashed) {
619     HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
620 
621     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
622       CertSize = 0;
623     } else {
624       if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
625         //
626         // Use PE32 offset.
627         //
628         CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
629       } else {
630         //
631         // Use PE32+ offset.
632         //
633         CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
634       }
635     }
636 
637     if (ImageSize > CertSize + SumOfBytesHashed) {
638       HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
639 
640       HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
641       if (!HashStatus) {
642         goto Finish;
643       }
644     } else if (ImageSize < CertSize + SumOfBytesHashed) {
645       goto Finish;
646     }
647   }
648 
649   //
650   // 17.  Finalize the SHA hash.
651   //
652   HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest);
653   if (!HashStatus) {
654     goto Finish;
655   }
656 
657   //
658   // Log the PE data
659   //
660   EventNumber = 1;
661   Status = TcgProtocol->HashLogExtendEvent (
662              TcgProtocol,
663              (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,
664              0,
665              TPM_ALG_SHA,
666              TcgEvent,
667              &EventNumber,
668              &EventLogLastEntry
669              );
670   if (Status == EFI_OUT_OF_RESOURCES) {
671     //
672     // Out of resource here means the image is hashed and its result is extended to PCR.
673     // But the event log cann't be saved since log area is full.
674     // Just return EFI_SUCCESS in order not to block the image load.
675     //
676     Status = EFI_SUCCESS;
677   }
678 
679 Finish:
680   FreePool (TcgEvent);
681 
682   if (SectionHeader != NULL) {
683     FreePool (SectionHeader);
684   }
685 
686   if (Sha1Ctx != NULL ) {
687     FreePool (Sha1Ctx);
688   }
689   return Status;
690 }
691 
692 /**
693   The security handler is used to abstract platform-specific policy
694   from the DXE core response to an attempt to use a file that returns a
695   given status for the authentication check from the section extraction protocol.
696 
697   The possible responses in a given SAP implementation may include locking
698   flash upon failure to authenticate, attestation logging for all signed drivers,
699   and other exception operations.  The File parameter allows for possible logging
700   within the SAP of the driver.
701 
702   If File is NULL, then EFI_INVALID_PARAMETER is returned.
703 
704   If the file specified by File with an authentication status specified by
705   AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
706 
707   If the file specified by File with an authentication status specified by
708   AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
709   then EFI_ACCESS_DENIED is returned.
710 
711   If the file specified by File with an authentication status specified by
712   AuthenticationStatus is not safe for the DXE Core to use right now, but it
713   might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
714   returned.
715 
716   @param[in]      AuthenticationStatus  This is the authentication status returned
717                                         from the securitymeasurement services for the
718                                         input file.
719   @param[in]      File       This is a pointer to the device path of the file that is
720                              being dispatched. This will optionally be used for logging.
721   @param[in]      FileBuffer File buffer matches the input file device path.
722   @param[in]      FileSize   Size of File buffer matches the input file device path.
723   @param[in]      BootPolicy A boot policy that was used to call LoadImage() UEFI service.
724 
725   @retval EFI_SUCCESS             The file specified by DevicePath and non-NULL
726                                   FileBuffer did authenticate, and the platform policy dictates
727                                   that the DXE Foundation may use the file.
728   @retval other error value
729 **/
730 EFI_STATUS
731 EFIAPI
DxeTpmMeasureBootHandler(IN UINT32 AuthenticationStatus,IN CONST EFI_DEVICE_PATH_PROTOCOL * File,IN VOID * FileBuffer,IN UINTN FileSize,IN BOOLEAN BootPolicy)732 DxeTpmMeasureBootHandler (
733   IN  UINT32                           AuthenticationStatus,
734   IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,
735   IN  VOID                             *FileBuffer,
736   IN  UINTN                            FileSize,
737   IN  BOOLEAN                          BootPolicy
738   )
739 {
740   EFI_TCG_PROTOCOL                    *TcgProtocol;
741   EFI_STATUS                          Status;
742   TCG_EFI_BOOT_SERVICE_CAPABILITY     ProtocolCapability;
743   UINT32                              TCGFeatureFlags;
744   EFI_PHYSICAL_ADDRESS                EventLogLocation;
745   EFI_PHYSICAL_ADDRESS                EventLogLastEntry;
746   EFI_DEVICE_PATH_PROTOCOL            *DevicePathNode;
747   EFI_DEVICE_PATH_PROTOCOL            *OrigDevicePathNode;
748   EFI_HANDLE                          Handle;
749   EFI_HANDLE                          TempHandle;
750   BOOLEAN                             ApplicationRequired;
751   PE_COFF_LOADER_IMAGE_CONTEXT        ImageContext;
752   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvbProtocol;
753   EFI_PHYSICAL_ADDRESS                FvAddress;
754   UINT32                              Index;
755 
756   Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
757   if (EFI_ERROR (Status)) {
758     //
759     // TCG protocol is not installed. So, TPM is not present.
760     // Don't do any measurement, and directly return EFI_SUCCESS.
761     //
762     return EFI_SUCCESS;
763   }
764 
765   ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);
766   Status = TcgProtocol->StatusCheck (
767              TcgProtocol,
768              &ProtocolCapability,
769              &TCGFeatureFlags,
770              &EventLogLocation,
771              &EventLogLastEntry
772            );
773   if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag || (!ProtocolCapability.TPMPresentFlag)) {
774     //
775     // TPM device doesn't work or activate.
776     //
777     return EFI_SUCCESS;
778   }
779 
780   //
781   // Copy File Device Path
782   //
783   OrigDevicePathNode = DuplicateDevicePath (File);
784 
785   //
786   // 1. Check whether this device path support BlockIo protocol.
787   // Is so, this device path may be a GPT device path.
788   //
789   DevicePathNode = OrigDevicePathNode;
790   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);
791   if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {
792     //
793     // Find the gpt partion on the given devicepath
794     //
795     DevicePathNode = OrigDevicePathNode;
796     ASSERT (DevicePathNode != NULL);
797     while (!IsDevicePathEnd (DevicePathNode)) {
798       //
799       // Find the Gpt partition
800       //
801       if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&
802             DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {
803         //
804         // Check whether it is a gpt partition or not
805         //
806         if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER &&
807             ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {
808 
809           //
810           // Change the partition device path to its parent device path (disk) and get the handle.
811           //
812           DevicePathNode->Type    = END_DEVICE_PATH_TYPE;
813           DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
814           DevicePathNode          = OrigDevicePathNode;
815           Status = gBS->LocateDevicePath (
816                          &gEfiDiskIoProtocolGuid,
817                          &DevicePathNode,
818                          &Handle
819                          );
820           if (!EFI_ERROR (Status)) {
821             //
822             // Measure GPT disk.
823             //
824             Status = TcgMeasureGptTable (TcgProtocol, Handle);
825             if (!EFI_ERROR (Status)) {
826               //
827               // GPT disk check done.
828               //
829               mMeasureGptTableFlag = TRUE;
830             }
831           }
832           FreePool (OrigDevicePathNode);
833           OrigDevicePathNode = DuplicateDevicePath (File);
834           ASSERT (OrigDevicePathNode != NULL);
835           break;
836         }
837       }
838       DevicePathNode    = NextDevicePathNode (DevicePathNode);
839     }
840   }
841 
842   //
843   // 2. Measure PE image.
844   //
845   ApplicationRequired = FALSE;
846 
847   //
848   // Check whether this device path support FVB protocol.
849   //
850   DevicePathNode = OrigDevicePathNode;
851   Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle);
852   if (!EFI_ERROR (Status)) {
853     //
854     // Don't check FV image, and directly return EFI_SUCCESS.
855     // It can be extended to the specific FV authentication according to the different requirement.
856     //
857     if (IsDevicePathEnd (DevicePathNode)) {
858       return EFI_SUCCESS;
859     }
860     //
861     // The PE image from unmeasured Firmware volume need be measured
862     // The PE image from measured Firmware volume will be mearsured according to policy below.
863     //   If it is driver, do not measure
864     //   If it is application, still measure.
865     //
866     ApplicationRequired = TRUE;
867 
868     if (mCacheMeasuredHandle != Handle && mMeasuredHobData != NULL) {
869       //
870       // Search for Root FV of this PE image
871       //
872       TempHandle = Handle;
873       do {
874         Status = gBS->HandleProtocol(
875                         TempHandle,
876                         &gEfiFirmwareVolumeBlockProtocolGuid,
877                         (VOID**)&FvbProtocol
878                         );
879         TempHandle = FvbProtocol->ParentHandle;
880       } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL);
881 
882       //
883       // Search in measured FV Hob
884       //
885       Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress);
886       if (EFI_ERROR(Status)){
887         return Status;
888       }
889 
890       ApplicationRequired = FALSE;
891 
892       for (Index = 0; Index < mMeasuredHobData->Num; Index++) {
893         if(mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {
894           //
895           // Cache measured FV for next measurement
896           //
897           mCacheMeasuredHandle = Handle;
898           ApplicationRequired  = TRUE;
899           break;
900         }
901       }
902     }
903   }
904 
905   //
906   // File is not found.
907   //
908   if (FileBuffer == NULL) {
909     Status = EFI_SECURITY_VIOLATION;
910     goto Finish;
911   }
912 
913   mTpmImageSize  = FileSize;
914   mFileBuffer = FileBuffer;
915 
916   //
917   // Measure PE Image
918   //
919   DevicePathNode = OrigDevicePathNode;
920   ZeroMem (&ImageContext, sizeof (ImageContext));
921   ImageContext.Handle    = (VOID *) FileBuffer;
922   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead;
923 
924   //
925   // Get information about the image being loaded
926   //
927   Status = PeCoffLoaderGetImageInfo (&ImageContext);
928   if (EFI_ERROR (Status)) {
929     //
930     // The information can't be got from the invalid PeImage
931     //
932     goto Finish;
933   }
934 
935   //
936   // Measure only application if Application flag is set
937   // Measure drivers and applications if Application flag is not set
938   //
939   if ((!ApplicationRequired) ||
940         (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
941     //
942     // Print the image path to be measured.
943     //
944     DEBUG_CODE_BEGIN ();
945       CHAR16                            *ToText;
946       ToText = ConvertDevicePathToText (
947                  DevicePathNode,
948                  FALSE,
949                  TRUE
950                  );
951       if (ToText != NULL) {
952         DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
953         FreePool (ToText);
954       }
955     DEBUG_CODE_END ();
956 
957     //
958     // Measure PE image into TPM log.
959     //
960     Status = TcgMeasurePeImage (
961                TcgProtocol,
962                (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer,
963                FileSize,
964                (UINTN) ImageContext.ImageAddress,
965                ImageContext.ImageType,
966                DevicePathNode
967                );
968   }
969 
970   //
971   // Done, free the allocated resource.
972   //
973 Finish:
974   if (OrigDevicePathNode != NULL) {
975     FreePool (OrigDevicePathNode);
976   }
977 
978   return Status;
979 }
980 
981 /**
982   Register the security handler to provide TPM measure boot service.
983 
984   @param  ImageHandle  ImageHandle of the loaded driver.
985   @param  SystemTable  Pointer to the EFI System Table.
986 
987   @retval  EFI_SUCCESS            Register successfully.
988   @retval  EFI_OUT_OF_RESOURCES   No enough memory to register this handler.
989 **/
990 EFI_STATUS
991 EFIAPI
DxeTpmMeasureBootLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)992 DxeTpmMeasureBootLibConstructor (
993   IN EFI_HANDLE        ImageHandle,
994   IN EFI_SYSTEM_TABLE  *SystemTable
995   )
996 {
997   EFI_HOB_GUID_TYPE  *GuidHob;
998 
999   GuidHob = NULL;
1000 
1001   GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);
1002 
1003   if (GuidHob != NULL) {
1004     mMeasuredHobData = GET_GUID_HOB_DATA (GuidHob);
1005   }
1006 
1007   return RegisterSecurity2Handler (
1008           DxeTpmMeasureBootHandler,
1009           EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
1010           );
1011 }
1012