2 This module implements measuring PeCoff image for Tcg2 Protocol.
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.
9 Copyright (c) 2015 - 2018, 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
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.
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>
32 UINTN mTcg2DxeImageSize
= 0;
35 Reads contents of a PE/COFF image in memory buffer.
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.
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.
47 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
54 IN OUT UINTN
*ReadSize
,
60 if (FileHandle
== NULL
|| ReadSize
== NULL
|| Buffer
== NULL
) {
61 return EFI_INVALID_PARAMETER
;
64 if (MAX_ADDRESS
- FileOffset
< *ReadSize
) {
65 return EFI_INVALID_PARAMETER
;
68 EndPosition
= FileOffset
+ *ReadSize
;
69 if (EndPosition
> mTcg2DxeImageSize
) {
70 *ReadSize
= (UINT32
)(mTcg2DxeImageSize
- FileOffset
);
73 if (FileOffset
>= mTcg2DxeImageSize
) {
77 CopyMem (Buffer
, (UINT8
*)((UINTN
) FileHandle
+ FileOffset
), *ReadSize
);
83 Measure PE image into TPM log based on the authenticode image hashing in
84 PE/COFF Specification 8.0 Appendix A.
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.
90 Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
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.
97 @retval EFI_SUCCESS Successfully measure image.
98 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
99 @retval other error value
102 MeasurePeImageAndExtend (
104 IN EFI_PHYSICAL_ADDRESS ImageAddress
,
106 OUT TPML_DIGEST_VALUES
*DigestList
110 EFI_IMAGE_DOS_HEADER
*DosHdr
;
111 UINT32 PeCoffHeaderOffset
;
112 EFI_IMAGE_SECTION_HEADER
*Section
;
115 UINTN SumOfBytesHashed
;
116 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
119 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
120 UINT32 NumberOfRvaAndSizes
;
122 HASH_HANDLE HashHandle
;
123 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
125 HashHandle
= 0xFFFFFFFF; // Know bad value
127 Status
= EFI_UNSUPPORTED
;
128 SectionHeader
= NULL
;
131 // Check PE/COFF image
133 ZeroMem (&ImageContext
, sizeof (ImageContext
));
134 ImageContext
.Handle
= (VOID
*) (UINTN
) ImageAddress
;
135 mTcg2DxeImageSize
= ImageSize
;
136 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) Tcg2DxeImageRead
;
139 // Get information about the image being loaded
141 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
142 if (EFI_ERROR (Status
)) {
144 // The information can't be got from the invalid PeImage
146 DEBUG ((DEBUG_INFO
, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));
150 DosHdr
= (EFI_IMAGE_DOS_HEADER
*) (UINTN
) ImageAddress
;
151 PeCoffHeaderOffset
= 0;
152 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
153 PeCoffHeaderOffset
= DosHdr
->e_lfanew
;
156 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINT8
*) (UINTN
) ImageAddress
+ PeCoffHeaderOffset
);
157 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
158 Status
= EFI_UNSUPPORTED
;
163 // PE/COFF Image Measurement
165 // NOTE: The following codes/steps are based upon the authenticode image hashing in
166 // PE/COFF Specification 8.0 Appendix A.
170 // 1. Load the image header into memory.
172 // 2. Initialize a SHA hash context.
174 Status
= HashStart (&HashHandle
);
175 if (EFI_ERROR (Status
)) {
180 // Measuring PE/COFF Image Header;
181 // But CheckSum field and SECURITY data directory (certificate) are excluded
185 // 3. Calculate the distance from the base of the image header to the image checksum address.
186 // 4. Hash the image header from its base to beginning of the image checksum.
188 HashBase
= (UINT8
*) (UINTN
) ImageAddress
;
189 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
193 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
194 HashSize
= (UINTN
) (&Hdr
.Pe32
->OptionalHeader
.CheckSum
) - (UINTN
) HashBase
;
199 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
200 HashSize
= (UINTN
) (&Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
) - (UINTN
) HashBase
;
203 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
204 if (EFI_ERROR (Status
)) {
209 // 5. Skip over the image checksum (it occupies a single ULONG).
211 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
) {
213 // 6. Since there is no Cert Directory in optional header, hash everything
214 // from the end of the checksum to the end of image header.
216 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
220 HashBase
= (UINT8
*) &Hdr
.Pe32
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
221 HashSize
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
226 HashBase
= (UINT8
*) &Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
227 HashSize
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
231 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
232 if (EFI_ERROR (Status
)) {
238 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
240 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
244 HashBase
= (UINT8
*) &Hdr
.Pe32
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
245 HashSize
= (UINTN
) (&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - (UINTN
) HashBase
;
250 HashBase
= (UINT8
*) &Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
251 HashSize
= (UINTN
) (&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - (UINTN
) HashBase
;
255 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
256 if (EFI_ERROR (Status
)) {
262 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
263 // 9. Hash everything from the end of the Cert Directory to the end of image header.
265 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
269 HashBase
= (UINT8
*) &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
270 HashSize
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
275 HashBase
= (UINT8
*) &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
276 HashSize
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
280 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
281 if (EFI_ERROR (Status
)) {
288 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
290 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
294 SumOfBytesHashed
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
299 SumOfBytesHashed
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
303 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
304 // structures in the image. The 'NumberOfSections' field of the image
305 // header indicates how big the table should be. Do not include any
306 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
308 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER
) * Hdr
.Pe32
->FileHeader
.NumberOfSections
);
309 if (SectionHeader
== NULL
) {
310 Status
= EFI_OUT_OF_RESOURCES
;
315 // 12. Using the 'PointerToRawData' in the referenced section headers as
316 // a key, arrange the elements in the table in ascending order. In other
317 // words, sort the section headers according to the disk-file offset of
320 Section
= (EFI_IMAGE_SECTION_HEADER
*) (
321 (UINT8
*) (UINTN
) ImageAddress
+
324 sizeof(EFI_IMAGE_FILE_HEADER
) +
325 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
327 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
329 while ((Pos
> 0) && (Section
->PointerToRawData
< SectionHeader
[Pos
- 1].PointerToRawData
)) {
330 CopyMem (&SectionHeader
[Pos
], &SectionHeader
[Pos
- 1], sizeof(EFI_IMAGE_SECTION_HEADER
));
333 CopyMem (&SectionHeader
[Pos
], Section
, sizeof(EFI_IMAGE_SECTION_HEADER
));
338 // 13. Walk through the sorted table, bring the corresponding section
339 // into memory, and hash the entire section (using the 'SizeOfRawData'
340 // field in the section header to determine the amount of data to hash).
341 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
342 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
344 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
345 Section
= (EFI_IMAGE_SECTION_HEADER
*) &SectionHeader
[Index
];
346 if (Section
->SizeOfRawData
== 0) {
349 HashBase
= (UINT8
*) (UINTN
) ImageAddress
+ Section
->PointerToRawData
;
350 HashSize
= (UINTN
) Section
->SizeOfRawData
;
352 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
353 if (EFI_ERROR (Status
)) {
357 SumOfBytesHashed
+= HashSize
;
361 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
362 // data in the file that needs to be added to the hash. This data begins
363 // at file offset SUM_OF_BYTES_HASHED and its length is:
364 // FileSize - (CertDirectory->Size)
366 if (ImageSize
> SumOfBytesHashed
) {
367 HashBase
= (UINT8
*) (UINTN
) ImageAddress
+ SumOfBytesHashed
;
369 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
) {
372 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
376 CertSize
= Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
;
381 CertSize
= Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
;
385 if (ImageSize
> CertSize
+ SumOfBytesHashed
) {
386 HashSize
= (UINTN
) (ImageSize
- CertSize
- SumOfBytesHashed
);
388 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
389 if (EFI_ERROR (Status
)) {
392 } else if (ImageSize
< CertSize
+ SumOfBytesHashed
) {
393 Status
= EFI_UNSUPPORTED
;
399 // 17. Finalize the SHA hash.
401 Status
= HashCompleteAndExtend (HashHandle
, PCRIndex
, NULL
, 0, DigestList
);
402 if (EFI_ERROR (Status
)) {
407 if (SectionHeader
!= NULL
) {
408 FreePool (SectionHeader
);