• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   This module implements measuring PeCoff image for TrEE Protocol.
3 
4   Caution: This file requires additional review when modified.
5   This driver will have external input - PE/COFF image.
6   This external input must be validated carefully to avoid security issue like
7   buffer overflow, integer overflow.
8 
9 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
10 This program and the accompanying materials
11 are licensed and made available under the terms and conditions of the BSD License
12 which accompanies this distribution.  The full text of the license may be found at
13 http://opensource.org/licenses/bsd-license.php
14 
15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 
18 **/
19 
20 #include <PiDxe.h>
21 
22 #include <Library/BaseLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/DevicePathLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/PeCoffLib.h>
29 #include <Library/Tpm2CommandLib.h>
30 #include <Library/HashLib.h>
31 
32 UINTN  mTrEEDxeImageSize = 0;
33 
34 /**
35   Reads contents of a PE/COFF image in memory buffer.
36 
37   Caution: This function may receive untrusted input.
38   PE/COFF image is external input, so this function will make sure the PE/COFF image content
39   read is within the image buffer.
40 
41   @param  FileHandle      Pointer to the file handle to read the PE/COFF image.
42   @param  FileOffset      Offset into the PE/COFF image to begin the read operation.
43   @param  ReadSize        On input, the size in bytes of the requested read operation.
44                           On output, the number of bytes actually read.
45   @param  Buffer          Output buffer that contains the data read from the PE/COFF image.
46 
47   @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size
48 **/
49 EFI_STATUS
50 EFIAPI
TrEEDxeImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)51 TrEEDxeImageRead (
52   IN     VOID    *FileHandle,
53   IN     UINTN   FileOffset,
54   IN OUT UINTN   *ReadSize,
55   OUT    VOID    *Buffer
56   )
57 {
58   UINTN               EndPosition;
59 
60   if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
61     return EFI_INVALID_PARAMETER;
62   }
63 
64   if (MAX_ADDRESS - FileOffset < *ReadSize) {
65     return EFI_INVALID_PARAMETER;
66   }
67 
68   EndPosition = FileOffset + *ReadSize;
69   if (EndPosition > mTrEEDxeImageSize) {
70     *ReadSize = (UINT32)(mTrEEDxeImageSize - FileOffset);
71   }
72 
73   if (FileOffset >= mTrEEDxeImageSize) {
74     *ReadSize = 0;
75   }
76 
77   CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
78 
79   return EFI_SUCCESS;
80 }
81 
82 /**
83   Measure PE image into TPM log based on the authenticode image hashing in
84   PE/COFF Specification 8.0 Appendix A.
85 
86   Caution: This function may receive untrusted input.
87   PE/COFF image is external input, so this function will validate its data structure
88   within this image buffer before use.
89 
90   Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
91 
92   @param[in]  PCRIndex       TPM PCR index
93   @param[in]  ImageAddress   Start address of image buffer.
94   @param[in]  ImageSize      Image size
95   @param[out] DigestList     Digeest list of this image.
96 
97   @retval EFI_SUCCESS            Successfully measure image.
98   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.
99   @retval other error value
100 **/
101 EFI_STATUS
MeasurePeImageAndExtend(IN UINT32 PCRIndex,IN EFI_PHYSICAL_ADDRESS ImageAddress,IN UINTN ImageSize,OUT TPML_DIGEST_VALUES * DigestList)102 MeasurePeImageAndExtend (
103   IN  UINT32                    PCRIndex,
104   IN  EFI_PHYSICAL_ADDRESS      ImageAddress,
105   IN  UINTN                     ImageSize,
106   OUT TPML_DIGEST_VALUES        *DigestList
107   )
108 {
109   EFI_STATUS                           Status;
110   EFI_IMAGE_DOS_HEADER                 *DosHdr;
111   UINT32                               PeCoffHeaderOffset;
112   EFI_IMAGE_SECTION_HEADER             *Section;
113   UINT8                                *HashBase;
114   UINTN                                HashSize;
115   UINTN                                SumOfBytesHashed;
116   EFI_IMAGE_SECTION_HEADER             *SectionHeader;
117   UINTN                                Index;
118   UINTN                                Pos;
119   UINT16                               Magic;
120   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
121   UINT32                               NumberOfRvaAndSizes;
122   UINT32                               CertSize;
123   HASH_HANDLE                          HashHandle;
124   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;
125 
126   HashHandle = 0xFFFFFFFF; // Know bad value
127 
128   Status        = EFI_UNSUPPORTED;
129   SectionHeader = NULL;
130 
131   //
132   // Check PE/COFF image
133   //
134   ZeroMem (&ImageContext, sizeof (ImageContext));
135   ImageContext.Handle    = (VOID *) (UINTN) ImageAddress;
136   mTrEEDxeImageSize      = ImageSize;
137   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) TrEEDxeImageRead;
138 
139   //
140   // Get information about the image being loaded
141   //
142   Status = PeCoffLoaderGetImageInfo (&ImageContext);
143   if (EFI_ERROR (Status)) {
144     //
145     // The information can't be got from the invalid PeImage
146     //
147     DEBUG ((DEBUG_INFO, "TreeDxe: PeImage invalid. Cannot retrieve image information.\n"));
148     goto Finish;
149   }
150 
151   DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
152   PeCoffHeaderOffset = 0;
153   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
154     PeCoffHeaderOffset = DosHdr->e_lfanew;
155   }
156 
157   Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
158   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
159     Status = EFI_UNSUPPORTED;
160     goto Finish;
161   }
162 
163   //
164   // PE/COFF Image Measurement
165   //
166   //    NOTE: The following codes/steps are based upon the authenticode image hashing in
167   //      PE/COFF Specification 8.0 Appendix A.
168   //
169   //
170 
171   // 1.  Load the image header into memory.
172 
173   // 2.  Initialize a SHA hash context.
174 
175   Status = HashStart (&HashHandle);
176   if (EFI_ERROR (Status)) {
177     goto Finish;
178   }
179 
180   //
181   // Measuring PE/COFF Image Header;
182   // But CheckSum field and SECURITY data directory (certificate) are excluded
183   //
184   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
185     //
186     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
187     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
188     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
189     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
190     //
191     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
192   } else {
193     //
194     // Get the magic value from the PE/COFF Optional Header
195     //
196     Magic = Hdr.Pe32->OptionalHeader.Magic;
197   }
198 
199   //
200   // 3.  Calculate the distance from the base of the image header to the image checksum address.
201   // 4.  Hash the image header from its base to beginning of the image checksum.
202   //
203   HashBase = (UINT8 *) (UINTN) ImageAddress;
204   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
205     //
206     // Use PE32 offset
207     //
208     NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
209     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
210   } else {
211     //
212     // Use PE32+ offset
213     //
214     NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
215     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
216   }
217 
218   Status = HashUpdate (HashHandle, HashBase, HashSize);
219   if (EFI_ERROR (Status)) {
220     goto Finish;
221   }
222 
223   //
224   // 5.  Skip over the image checksum (it occupies a single ULONG).
225   //
226   if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
227     //
228     // 6.  Since there is no Cert Directory in optional header, hash everything
229     //     from the end of the checksum to the end of image header.
230     //
231     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
232       //
233       // Use PE32 offset.
234       //
235       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
236       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
237     } else {
238       //
239       // Use PE32+ offset.
240       //
241       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
242       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
243     }
244 
245     if (HashSize != 0) {
246       Status  = HashUpdate (HashHandle, HashBase, HashSize);
247       if (EFI_ERROR (Status)) {
248         goto Finish;
249       }
250     }
251   } else {
252     //
253     // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
254     //
255     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
256       //
257       // Use PE32 offset
258       //
259       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
260       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
261     } else {
262       //
263       // Use PE32+ offset
264       //
265       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
266       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
267     }
268 
269     if (HashSize != 0) {
270       Status  = HashUpdate (HashHandle, HashBase, HashSize);
271       if (EFI_ERROR (Status)) {
272         goto Finish;
273       }
274     }
275 
276     //
277     // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
278     // 9.  Hash everything from the end of the Cert Directory to the end of image header.
279     //
280     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
281       //
282       // Use PE32 offset
283       //
284       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
285       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
286     } else {
287       //
288       // Use PE32+ offset
289       //
290       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
291       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
292     }
293 
294     if (HashSize != 0) {
295       Status  = HashUpdate (HashHandle, HashBase, HashSize);
296       if (EFI_ERROR (Status)) {
297         goto Finish;
298       }
299     }
300   }
301 
302   //
303   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
304   //
305   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
306     //
307     // Use PE32 offset
308     //
309     SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
310   } else {
311     //
312     // Use PE32+ offset
313     //
314     SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
315   }
316 
317   //
318   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
319   //     structures in the image. The 'NumberOfSections' field of the image
320   //     header indicates how big the table should be. Do not include any
321   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
322   //
323   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
324   if (SectionHeader == NULL) {
325     Status = EFI_OUT_OF_RESOURCES;
326     goto Finish;
327   }
328 
329   //
330   // 12.  Using the 'PointerToRawData' in the referenced section headers as
331   //      a key, arrange the elements in the table in ascending order. In other
332   //      words, sort the section headers according to the disk-file offset of
333   //      the section.
334   //
335   Section = (EFI_IMAGE_SECTION_HEADER *) (
336                (UINT8 *) (UINTN) ImageAddress +
337                PeCoffHeaderOffset +
338                sizeof(UINT32) +
339                sizeof(EFI_IMAGE_FILE_HEADER) +
340                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
341                );
342   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
343     Pos = Index;
344     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
345       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
346       Pos--;
347     }
348     CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
349     Section += 1;
350   }
351 
352   //
353   // 13.  Walk through the sorted table, bring the corresponding section
354   //      into memory, and hash the entire section (using the 'SizeOfRawData'
355   //      field in the section header to determine the amount of data to hash).
356   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
357   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
358   //
359   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
360     Section  = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
361     if (Section->SizeOfRawData == 0) {
362       continue;
363     }
364     HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
365     HashSize = (UINTN) Section->SizeOfRawData;
366 
367     Status = HashUpdate (HashHandle, HashBase, HashSize);
368     if (EFI_ERROR (Status)) {
369       goto Finish;
370     }
371 
372     SumOfBytesHashed += HashSize;
373   }
374 
375   //
376   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
377   //      data in the file that needs to be added to the hash. This data begins
378   //      at file offset SUM_OF_BYTES_HASHED and its length is:
379   //             FileSize  -  (CertDirectory->Size)
380   //
381   if (ImageSize > SumOfBytesHashed) {
382     HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
383 
384     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
385       CertSize = 0;
386     } else {
387       if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
388         //
389         // Use PE32 offset.
390         //
391         CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
392       } else {
393         //
394         // Use PE32+ offset.
395         //
396         CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
397       }
398     }
399 
400     if (ImageSize > CertSize + SumOfBytesHashed) {
401       HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
402 
403       Status = HashUpdate (HashHandle, HashBase, HashSize);
404       if (EFI_ERROR (Status)) {
405         goto Finish;
406       }
407     } else if (ImageSize < CertSize + SumOfBytesHashed) {
408       Status = EFI_UNSUPPORTED;
409       goto Finish;
410     }
411   }
412 
413   //
414   // 17.  Finalize the SHA hash.
415   //
416   Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);
417   if (EFI_ERROR (Status)) {
418     goto Finish;
419   }
420 
421 Finish:
422   if (SectionHeader != NULL) {
423     FreePool (SectionHeader);
424   }
425 
426   return Status;
427 }
428