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