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