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 SPDX-License-Identifier: BSD-2-Clause-Patent
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/DevicePathLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/PeCoffLib.h>
23 #include <Library/Tpm2CommandLib.h>
24 #include <Library/HashLib.h>
26 UINTN mTcg2DxeImageSize
= 0;
29 Reads contents of a PE/COFF image in memory buffer.
31 Caution: This function may receive untrusted input.
32 PE/COFF image is external input, so this function will make sure the PE/COFF image content
33 read is within the image buffer.
35 @param FileHandle Pointer to the file handle to read the PE/COFF image.
36 @param FileOffset Offset into the PE/COFF image to begin the read operation.
37 @param ReadSize On input, the size in bytes of the requested read operation.
38 On output, the number of bytes actually read.
39 @param Buffer Output buffer that contains the data read from the PE/COFF image.
41 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
48 IN OUT UINTN
*ReadSize
,
54 if (FileHandle
== NULL
|| ReadSize
== NULL
|| Buffer
== NULL
) {
55 return EFI_INVALID_PARAMETER
;
58 if (MAX_ADDRESS
- FileOffset
< *ReadSize
) {
59 return EFI_INVALID_PARAMETER
;
62 EndPosition
= FileOffset
+ *ReadSize
;
63 if (EndPosition
> mTcg2DxeImageSize
) {
64 *ReadSize
= (UINT32
)(mTcg2DxeImageSize
- FileOffset
);
67 if (FileOffset
>= mTcg2DxeImageSize
) {
71 CopyMem (Buffer
, (UINT8
*)((UINTN
) FileHandle
+ FileOffset
), *ReadSize
);
77 Measure PE image into TPM log based on the authenticode image hashing in
78 PE/COFF Specification 8.0 Appendix A.
80 Caution: This function may receive untrusted input.
81 PE/COFF image is external input, so this function will validate its data structure
82 within this image buffer before use.
84 Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
86 @param[in] PCRIndex TPM PCR index
87 @param[in] ImageAddress Start address of image buffer.
88 @param[in] ImageSize Image size
89 @param[out] DigestList Digest list of this image.
91 @retval EFI_SUCCESS Successfully measure image.
92 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
93 @retval other error value
96 MeasurePeImageAndExtend (
98 IN EFI_PHYSICAL_ADDRESS ImageAddress
,
100 OUT TPML_DIGEST_VALUES
*DigestList
104 EFI_IMAGE_DOS_HEADER
*DosHdr
;
105 UINT32 PeCoffHeaderOffset
;
106 EFI_IMAGE_SECTION_HEADER
*Section
;
109 UINTN SumOfBytesHashed
;
110 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
113 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
114 UINT32 NumberOfRvaAndSizes
;
116 HASH_HANDLE HashHandle
;
117 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
119 HashHandle
= 0xFFFFFFFF; // Know bad value
121 Status
= EFI_UNSUPPORTED
;
122 SectionHeader
= NULL
;
125 // Check PE/COFF image
127 ZeroMem (&ImageContext
, sizeof (ImageContext
));
128 ImageContext
.Handle
= (VOID
*) (UINTN
) ImageAddress
;
129 mTcg2DxeImageSize
= ImageSize
;
130 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) Tcg2DxeImageRead
;
133 // Get information about the image being loaded
135 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
136 if (EFI_ERROR (Status
)) {
138 // The information can't be got from the invalid PeImage
140 DEBUG ((DEBUG_INFO
, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));
144 DosHdr
= (EFI_IMAGE_DOS_HEADER
*) (UINTN
) ImageAddress
;
145 PeCoffHeaderOffset
= 0;
146 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
147 PeCoffHeaderOffset
= DosHdr
->e_lfanew
;
150 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINT8
*) (UINTN
) ImageAddress
+ PeCoffHeaderOffset
);
151 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
152 Status
= EFI_UNSUPPORTED
;
157 // PE/COFF Image Measurement
159 // NOTE: The following codes/steps are based upon the authenticode image hashing in
160 // PE/COFF Specification 8.0 Appendix A.
164 // 1. Load the image header into memory.
166 // 2. Initialize a SHA hash context.
168 Status
= HashStart (&HashHandle
);
169 if (EFI_ERROR (Status
)) {
174 // Measuring PE/COFF Image Header;
175 // But CheckSum field and SECURITY data directory (certificate) are excluded
179 // 3. Calculate the distance from the base of the image header to the image checksum address.
180 // 4. Hash the image header from its base to beginning of the image checksum.
182 HashBase
= (UINT8
*) (UINTN
) ImageAddress
;
183 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
187 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
188 HashSize
= (UINTN
) (&Hdr
.Pe32
->OptionalHeader
.CheckSum
) - (UINTN
) HashBase
;
193 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
194 HashSize
= (UINTN
) (&Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
) - (UINTN
) HashBase
;
197 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
198 if (EFI_ERROR (Status
)) {
203 // 5. Skip over the image checksum (it occupies a single ULONG).
205 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
) {
207 // 6. Since there is no Cert Directory in optional header, hash everything
208 // from the end of the checksum to the end of image header.
210 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
214 HashBase
= (UINT8
*) &Hdr
.Pe32
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
215 HashSize
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
220 HashBase
= (UINT8
*) &Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
221 HashSize
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
225 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
226 if (EFI_ERROR (Status
)) {
232 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
234 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
238 HashBase
= (UINT8
*) &Hdr
.Pe32
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
239 HashSize
= (UINTN
) (&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - (UINTN
) HashBase
;
244 HashBase
= (UINT8
*) &Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
245 HashSize
= (UINTN
) (&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - (UINTN
) HashBase
;
249 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
250 if (EFI_ERROR (Status
)) {
256 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
257 // 9. Hash everything from the end of the Cert Directory to the end of image header.
259 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
263 HashBase
= (UINT8
*) &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
264 HashSize
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
269 HashBase
= (UINT8
*) &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
270 HashSize
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- (UINTN
) (HashBase
- ImageAddress
);
274 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
275 if (EFI_ERROR (Status
)) {
282 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
284 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
288 SumOfBytesHashed
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
293 SumOfBytesHashed
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
297 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
298 // structures in the image. The 'NumberOfSections' field of the image
299 // header indicates how big the table should be. Do not include any
300 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
302 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER
) * Hdr
.Pe32
->FileHeader
.NumberOfSections
);
303 if (SectionHeader
== NULL
) {
304 Status
= EFI_OUT_OF_RESOURCES
;
309 // 12. Using the 'PointerToRawData' in the referenced section headers as
310 // a key, arrange the elements in the table in ascending order. In other
311 // words, sort the section headers according to the disk-file offset of
314 Section
= (EFI_IMAGE_SECTION_HEADER
*) (
315 (UINT8
*) (UINTN
) ImageAddress
+
318 sizeof(EFI_IMAGE_FILE_HEADER
) +
319 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
321 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
323 while ((Pos
> 0) && (Section
->PointerToRawData
< SectionHeader
[Pos
- 1].PointerToRawData
)) {
324 CopyMem (&SectionHeader
[Pos
], &SectionHeader
[Pos
- 1], sizeof(EFI_IMAGE_SECTION_HEADER
));
327 CopyMem (&SectionHeader
[Pos
], Section
, sizeof(EFI_IMAGE_SECTION_HEADER
));
332 // 13. Walk through the sorted table, bring the corresponding section
333 // into memory, and hash the entire section (using the 'SizeOfRawData'
334 // field in the section header to determine the amount of data to hash).
335 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
336 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
338 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
339 Section
= (EFI_IMAGE_SECTION_HEADER
*) &SectionHeader
[Index
];
340 if (Section
->SizeOfRawData
== 0) {
343 HashBase
= (UINT8
*) (UINTN
) ImageAddress
+ Section
->PointerToRawData
;
344 HashSize
= (UINTN
) Section
->SizeOfRawData
;
346 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
347 if (EFI_ERROR (Status
)) {
351 SumOfBytesHashed
+= HashSize
;
355 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
356 // data in the file that needs to be added to the hash. This data begins
357 // at file offset SUM_OF_BYTES_HASHED and its length is:
358 // FileSize - (CertDirectory->Size)
360 if (ImageSize
> SumOfBytesHashed
) {
361 HashBase
= (UINT8
*) (UINTN
) ImageAddress
+ SumOfBytesHashed
;
363 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
) {
366 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
370 CertSize
= Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
;
375 CertSize
= Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
;
379 if (ImageSize
> CertSize
+ SumOfBytesHashed
) {
380 HashSize
= (UINTN
) (ImageSize
- CertSize
- SumOfBytesHashed
);
382 Status
= HashUpdate (HashHandle
, HashBase
, HashSize
);
383 if (EFI_ERROR (Status
)) {
386 } else if (ImageSize
< CertSize
+ SumOfBytesHashed
) {
387 Status
= EFI_UNSUPPORTED
;
393 // 17. Finalize the SHA hash.
395 Status
= HashCompleteAndExtend (HashHandle
, PCRIndex
, NULL
, 0, DigestList
);
396 if (EFI_ERROR (Status
)) {
401 if (SectionHeader
!= NULL
) {
402 FreePool (SectionHeader
);