SecurityPkg: remove PE/COFF header workaround for ELILO on IPF
[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
LG
9Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
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
1abfa4ce
JY
13http://opensource.org/licenses/bsd-license.php\r
14\r
b3548d32 15THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
1abfa4ce
JY
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
5a8eae95
LG
32UINTN mTcg2DxeImageSize = 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
51Tcg2DxeImageRead (\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 > mTcg2DxeImageSize) {\r
70 *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset);\r
71 }\r
72\r
73 if (FileOffset >= mTcg2DxeImageSize) {\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
1abfa4ce
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
5a8eae95
LG
90 Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().\r
91\r
1abfa4ce
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
1abfa4ce
JY
119 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
120 UINT32 NumberOfRvaAndSizes;\r
121 UINT32 CertSize;\r
122 HASH_HANDLE HashHandle;\r
5a8eae95 123 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
1abfa4ce
JY
124\r
125 HashHandle = 0xFFFFFFFF; // Know bad value\r
126\r
127 Status = EFI_UNSUPPORTED;\r
128 SectionHeader = NULL;\r
129\r
130 //\r
131 // Check PE/COFF image\r
132 //\r
5a8eae95
LG
133 ZeroMem (&ImageContext, sizeof (ImageContext));\r
134 ImageContext.Handle = (VOID *) (UINTN) ImageAddress;\r
135 mTcg2DxeImageSize = ImageSize;\r
136 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) Tcg2DxeImageRead;\r
137\r
138 //\r
139 // Get information about the image being loaded\r
140 //\r
141 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
142 if (EFI_ERROR (Status)) {\r
143 //\r
144 // The information can't be got from the invalid PeImage\r
145 //\r
146 DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));\r
147 goto Finish;\r
148 }\r
149\r
1abfa4ce
JY
150 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
151 PeCoffHeaderOffset = 0;\r
152 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
153 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
154 }\r
155\r
156 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
157 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
158 Status = EFI_UNSUPPORTED;\r
159 goto Finish;\r
160 }\r
161\r
162 //\r
163 // PE/COFF Image Measurement\r
164 //\r
165 // NOTE: The following codes/steps are based upon the authenticode image hashing in\r
166 // PE/COFF Specification 8.0 Appendix A.\r
167 //\r
168 //\r
169\r
170 // 1. Load the image header into memory.\r
171\r
172 // 2. Initialize a SHA hash context.\r
173\r
174 Status = HashStart (&HashHandle);\r
175 if (EFI_ERROR (Status)) {\r
176 goto Finish;\r
177 }\r
178\r
179 //\r
180 // Measuring PE/COFF Image Header;\r
181 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
182 //\r
b3548d32 183\r
1abfa4ce
JY
184 //\r
185 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
186 // 4. Hash the image header from its base to beginning of the image checksum.\r
187 //\r
188 HashBase = (UINT8 *) (UINTN) ImageAddress;\r
f199664c 189 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1abfa4ce
JY
190 //\r
191 // Use PE32 offset\r
192 //\r
193 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
4333b99d 194 HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
1abfa4ce
JY
195 } else {\r
196 //\r
197 // Use PE32+ offset\r
198 //\r
199 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
4333b99d 200 HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
1abfa4ce
JY
201 }\r
202\r
203 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
204 if (EFI_ERROR (Status)) {\r
205 goto Finish;\r
b3548d32 206 }\r
1abfa4ce
JY
207\r
208 //\r
209 // 5. Skip over the image checksum (it occupies a single ULONG).\r
210 //\r
211 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
212 //\r
213 // 6. Since there is no Cert Directory in optional header, hash everything\r
214 // from the end of the checksum to the end of image header.\r
215 //\r
f199664c 216 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1abfa4ce
JY
217 //\r
218 // Use PE32 offset.\r
219 //\r
220 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
221 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
222 } else {\r
223 //\r
224 // Use PE32+ offset.\r
225 //\r
226 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
227 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
228 }\r
229\r
230 if (HashSize != 0) {\r
231 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
232 if (EFI_ERROR (Status)) {\r
233 goto Finish;\r
234 }\r
b3548d32 235 }\r
1abfa4ce
JY
236 } else {\r
237 //\r
238 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
239 //\r
f199664c 240 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1abfa4ce
JY
241 //\r
242 // Use PE32 offset\r
243 //\r
244 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 245 HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
1abfa4ce
JY
246 } else {\r
247 //\r
248 // Use PE32+ offset\r
b3548d32 249 //\r
1abfa4ce 250 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 251 HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
1abfa4ce
JY
252 }\r
253\r
254 if (HashSize != 0) {\r
255 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
256 if (EFI_ERROR (Status)) {\r
257 goto Finish;\r
258 }\r
259 }\r
260\r
261 //\r
262 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
263 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
264 //\r
f199664c 265 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1abfa4ce
JY
266 //\r
267 // Use PE32 offset\r
268 //\r
269 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
270 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
271 } else {\r
272 //\r
273 // Use PE32+ offset\r
274 //\r
275 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
276 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
277 }\r
b3548d32 278\r
1abfa4ce
JY
279 if (HashSize != 0) {\r
280 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
281 if (EFI_ERROR (Status)) {\r
282 goto Finish;\r
283 }\r
284 }\r
285 }\r
286\r
287 //\r
288 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header\r
289 //\r
f199664c 290 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1abfa4ce
JY
291 //\r
292 // Use PE32 offset\r
293 //\r
294 SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
295 } else {\r
296 //\r
297 // Use PE32+ offset\r
298 //\r
299 SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
300 }\r
301\r
302 //\r
303 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
304 // structures in the image. The 'NumberOfSections' field of the image\r
305 // header indicates how big the table should be. Do not include any\r
306 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
307 //\r
308 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
309 if (SectionHeader == NULL) {\r
310 Status = EFI_OUT_OF_RESOURCES;\r
311 goto Finish;\r
312 }\r
313\r
314 //\r
315 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
316 // a key, arrange the elements in the table in ascending order. In other\r
317 // words, sort the section headers according to the disk-file offset of\r
318 // the section.\r
319 //\r
320 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
321 (UINT8 *) (UINTN) ImageAddress +\r
322 PeCoffHeaderOffset +\r
323 sizeof(UINT32) +\r
324 sizeof(EFI_IMAGE_FILE_HEADER) +\r
325 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
326 );\r
327 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
328 Pos = Index;\r
329 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
330 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));\r
331 Pos--;\r
332 }\r
333 CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));\r
334 Section += 1;\r
335 }\r
336\r
337 //\r
338 // 13. Walk through the sorted table, bring the corresponding section\r
339 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
340 // field in the section header to determine the amount of data to hash).\r
341 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
342 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
343 //\r
344 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
345 Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];\r
346 if (Section->SizeOfRawData == 0) {\r
347 continue;\r
348 }\r
349 HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;\r
350 HashSize = (UINTN) Section->SizeOfRawData;\r
351\r
352 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
353 if (EFI_ERROR (Status)) {\r
354 goto Finish;\r
355 }\r
356\r
357 SumOfBytesHashed += HashSize;\r
358 }\r
359\r
360 //\r
361 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
362 // data in the file that needs to be added to the hash. This data begins\r
363 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
364 // FileSize - (CertDirectory->Size)\r
365 //\r
366 if (ImageSize > SumOfBytesHashed) {\r
367 HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
368\r
369 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
370 CertSize = 0;\r
371 } else {\r
f199664c 372 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1abfa4ce
JY
373 //\r
374 // Use PE32 offset.\r
375 //\r
376 CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
377 } else {\r
378 //\r
379 // Use PE32+ offset.\r
380 //\r
381 CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
382 }\r
383 }\r
384\r
385 if (ImageSize > CertSize + SumOfBytesHashed) {\r
386 HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);\r
387\r
388 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
389 if (EFI_ERROR (Status)) {\r
390 goto Finish;\r
391 }\r
392 } else if (ImageSize < CertSize + SumOfBytesHashed) {\r
393 Status = EFI_UNSUPPORTED;\r
394 goto Finish;\r
395 }\r
396 }\r
397\r
398 //\r
399 // 17. Finalize the SHA hash.\r
400 //\r
401 Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);\r
402 if (EFI_ERROR (Status)) {\r
403 goto Finish;\r
404 }\r
405\r
406Finish:\r
407 if (SectionHeader != NULL) {\r
408 FreePool (SectionHeader);\r
409 }\r
410\r
411 return Status;\r
412}\r