]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c
SecurityPkg: Fix spelling errors
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Dxe / MeasureBootPeCoff.c
1 /** @file
2 This module implements measuring PeCoff image for Tcg2 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) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
10 SPDX-License-Identifier: BSD-2-Clause-Patent
11
12 **/
13
14 #include <PiDxe.h>
15
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>
25
26 UINTN mTcg2DxeImageSize = 0;
27
28 /**
29 Reads contents of a PE/COFF image in memory buffer.
30
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.
34
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.
40
41 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
42 **/
43 EFI_STATUS
44 EFIAPI
45 Tcg2DxeImageRead (
46 IN VOID *FileHandle,
47 IN UINTN FileOffset,
48 IN OUT UINTN *ReadSize,
49 OUT VOID *Buffer
50 )
51 {
52 UINTN EndPosition;
53
54 if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
55 return EFI_INVALID_PARAMETER;
56 }
57
58 if (MAX_ADDRESS - FileOffset < *ReadSize) {
59 return EFI_INVALID_PARAMETER;
60 }
61
62 EndPosition = FileOffset + *ReadSize;
63 if (EndPosition > mTcg2DxeImageSize) {
64 *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset);
65 }
66
67 if (FileOffset >= mTcg2DxeImageSize) {
68 *ReadSize = 0;
69 }
70
71 CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
72
73 return EFI_SUCCESS;
74 }
75
76 /**
77 Measure PE image into TPM log based on the authenticode image hashing in
78 PE/COFF Specification 8.0 Appendix A.
79
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.
83
84 Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
85
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.
90
91 @retval EFI_SUCCESS Successfully measure image.
92 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
93 @retval other error value
94 **/
95 EFI_STATUS
96 MeasurePeImageAndExtend (
97 IN UINT32 PCRIndex,
98 IN EFI_PHYSICAL_ADDRESS ImageAddress,
99 IN UINTN ImageSize,
100 OUT TPML_DIGEST_VALUES *DigestList
101 )
102 {
103 EFI_STATUS Status;
104 EFI_IMAGE_DOS_HEADER *DosHdr;
105 UINT32 PeCoffHeaderOffset;
106 EFI_IMAGE_SECTION_HEADER *Section;
107 UINT8 *HashBase;
108 UINTN HashSize;
109 UINTN SumOfBytesHashed;
110 EFI_IMAGE_SECTION_HEADER *SectionHeader;
111 UINTN Index;
112 UINTN Pos;
113 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
114 UINT32 NumberOfRvaAndSizes;
115 UINT32 CertSize;
116 HASH_HANDLE HashHandle;
117 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
118
119 HashHandle = 0xFFFFFFFF; // Know bad value
120
121 Status = EFI_UNSUPPORTED;
122 SectionHeader = NULL;
123
124 //
125 // Check PE/COFF image
126 //
127 ZeroMem (&ImageContext, sizeof (ImageContext));
128 ImageContext.Handle = (VOID *) (UINTN) ImageAddress;
129 mTcg2DxeImageSize = ImageSize;
130 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) Tcg2DxeImageRead;
131
132 //
133 // Get information about the image being loaded
134 //
135 Status = PeCoffLoaderGetImageInfo (&ImageContext);
136 if (EFI_ERROR (Status)) {
137 //
138 // The information can't be got from the invalid PeImage
139 //
140 DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));
141 goto Finish;
142 }
143
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;
148 }
149
150 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
151 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
152 Status = EFI_UNSUPPORTED;
153 goto Finish;
154 }
155
156 //
157 // PE/COFF Image Measurement
158 //
159 // NOTE: The following codes/steps are based upon the authenticode image hashing in
160 // PE/COFF Specification 8.0 Appendix A.
161 //
162 //
163
164 // 1. Load the image header into memory.
165
166 // 2. Initialize a SHA hash context.
167
168 Status = HashStart (&HashHandle);
169 if (EFI_ERROR (Status)) {
170 goto Finish;
171 }
172
173 //
174 // Measuring PE/COFF Image Header;
175 // But CheckSum field and SECURITY data directory (certificate) are excluded
176 //
177
178 //
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.
181 //
182 HashBase = (UINT8 *) (UINTN) ImageAddress;
183 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
184 //
185 // Use PE32 offset
186 //
187 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
188 HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
189 } else {
190 //
191 // Use PE32+ offset
192 //
193 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
194 HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
195 }
196
197 Status = HashUpdate (HashHandle, HashBase, HashSize);
198 if (EFI_ERROR (Status)) {
199 goto Finish;
200 }
201
202 //
203 // 5. Skip over the image checksum (it occupies a single ULONG).
204 //
205 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
206 //
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.
209 //
210 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
211 //
212 // Use PE32 offset.
213 //
214 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
215 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
216 } else {
217 //
218 // Use PE32+ offset.
219 //
220 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
221 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
222 }
223
224 if (HashSize != 0) {
225 Status = HashUpdate (HashHandle, HashBase, HashSize);
226 if (EFI_ERROR (Status)) {
227 goto Finish;
228 }
229 }
230 } else {
231 //
232 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
233 //
234 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
235 //
236 // Use PE32 offset
237 //
238 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
239 HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
240 } else {
241 //
242 // Use PE32+ offset
243 //
244 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
245 HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
246 }
247
248 if (HashSize != 0) {
249 Status = HashUpdate (HashHandle, HashBase, HashSize);
250 if (EFI_ERROR (Status)) {
251 goto Finish;
252 }
253 }
254
255 //
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.
258 //
259 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
260 //
261 // Use PE32 offset
262 //
263 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
264 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
265 } else {
266 //
267 // Use PE32+ offset
268 //
269 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
270 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
271 }
272
273 if (HashSize != 0) {
274 Status = HashUpdate (HashHandle, HashBase, HashSize);
275 if (EFI_ERROR (Status)) {
276 goto Finish;
277 }
278 }
279 }
280
281 //
282 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
283 //
284 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
285 //
286 // Use PE32 offset
287 //
288 SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
289 } else {
290 //
291 // Use PE32+ offset
292 //
293 SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
294 }
295
296 //
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.
301 //
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;
305 goto Finish;
306 }
307
308 //
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
312 // the section.
313 //
314 Section = (EFI_IMAGE_SECTION_HEADER *) (
315 (UINT8 *) (UINTN) ImageAddress +
316 PeCoffHeaderOffset +
317 sizeof(UINT32) +
318 sizeof(EFI_IMAGE_FILE_HEADER) +
319 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
320 );
321 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
322 Pos = Index;
323 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
324 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
325 Pos--;
326 }
327 CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
328 Section += 1;
329 }
330
331 //
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.
337 //
338 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
339 Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
340 if (Section->SizeOfRawData == 0) {
341 continue;
342 }
343 HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
344 HashSize = (UINTN) Section->SizeOfRawData;
345
346 Status = HashUpdate (HashHandle, HashBase, HashSize);
347 if (EFI_ERROR (Status)) {
348 goto Finish;
349 }
350
351 SumOfBytesHashed += HashSize;
352 }
353
354 //
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)
359 //
360 if (ImageSize > SumOfBytesHashed) {
361 HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
362
363 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
364 CertSize = 0;
365 } else {
366 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
367 //
368 // Use PE32 offset.
369 //
370 CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
371 } else {
372 //
373 // Use PE32+ offset.
374 //
375 CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
376 }
377 }
378
379 if (ImageSize > CertSize + SumOfBytesHashed) {
380 HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
381
382 Status = HashUpdate (HashHandle, HashBase, HashSize);
383 if (EFI_ERROR (Status)) {
384 goto Finish;
385 }
386 } else if (ImageSize < CertSize + SumOfBytesHashed) {
387 Status = EFI_UNSUPPORTED;
388 goto Finish;
389 }
390 }
391
392 //
393 // 17. Finalize the SHA hash.
394 //
395 Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);
396 if (EFI_ERROR (Status)) {
397 goto Finish;
398 }
399
400 Finish:
401 if (SectionHeader != NULL) {
402 FreePool (SectionHeader);
403 }
404
405 return Status;
406 }