]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c
SecurityPkg TrEEDxe: Add check for the PE/COFF image.
[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
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
9Copyright (c) 2015, 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
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
32/**\r
33 Measure PE image into TPM log based on the authenticode image hashing in\r
34 PE/COFF Specification 8.0 Appendix A.\r
35\r
36 Caution: This function may receive untrusted input.\r
37 PE/COFF image is external input, so this function will validate its data structure\r
38 within this image buffer before use.\r
39\r
40 @param[in] PCRIndex TPM PCR index\r
41 @param[in] ImageAddress Start address of image buffer.\r
42 @param[in] ImageSize Image size\r
43 @param[out] DigestList Digeest list of this image.\r
44\r
45 @retval EFI_SUCCESS Successfully measure image.\r
46 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.\r
47 @retval other error value\r
48**/\r
49EFI_STATUS\r
50MeasurePeImageAndExtend (\r
51 IN UINT32 PCRIndex,\r
52 IN EFI_PHYSICAL_ADDRESS ImageAddress,\r
53 IN UINTN ImageSize,\r
54 OUT TPML_DIGEST_VALUES *DigestList\r
55 )\r
56{\r
57 EFI_STATUS Status;\r
58 EFI_IMAGE_DOS_HEADER *DosHdr;\r
59 UINT32 PeCoffHeaderOffset;\r
60 EFI_IMAGE_SECTION_HEADER *Section;\r
61 UINT8 *HashBase;\r
62 UINTN HashSize;\r
63 UINTN SumOfBytesHashed;\r
64 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
65 UINTN Index;\r
66 UINTN Pos;\r
67 UINT16 Magic;\r
68 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
69 UINT32 NumberOfRvaAndSizes;\r
70 UINT32 CertSize;\r
71 HASH_HANDLE HashHandle;\r
72\r
73 HashHandle = 0xFFFFFFFF; // Know bad value\r
74\r
75 Status = EFI_UNSUPPORTED;\r
76 SectionHeader = NULL;\r
77\r
78 //\r
79 // Check PE/COFF image\r
80 //\r
81 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
82 PeCoffHeaderOffset = 0;\r
83 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
84 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
85 }\r
86\r
87 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
88 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
89 Status = EFI_UNSUPPORTED;\r
90 goto Finish;\r
91 }\r
92\r
93 //\r
94 // PE/COFF Image Measurement\r
95 //\r
96 // NOTE: The following codes/steps are based upon the authenticode image hashing in\r
97 // PE/COFF Specification 8.0 Appendix A.\r
98 //\r
99 //\r
100\r
101 // 1. Load the image header into memory.\r
102\r
103 // 2. Initialize a SHA hash context.\r
104\r
105 Status = HashStart (&HashHandle);\r
106 if (EFI_ERROR (Status)) {\r
107 goto Finish;\r
108 }\r
109\r
110 //\r
111 // Measuring PE/COFF Image Header;\r
112 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
113 //\r
114 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
115 //\r
116 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
117 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
118 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
119 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
120 //\r
121 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
122 } else {\r
123 //\r
124 // Get the magic value from the PE/COFF Optional Header\r
125 //\r
126 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
127 }\r
128 \r
129 //\r
130 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
131 // 4. Hash the image header from its base to beginning of the image checksum.\r
132 //\r
133 HashBase = (UINT8 *) (UINTN) ImageAddress;\r
134 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
135 //\r
136 // Use PE32 offset\r
137 //\r
138 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
139 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);\r
140 } else {\r
141 //\r
142 // Use PE32+ offset\r
143 //\r
144 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
145 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
146 }\r
147\r
148 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
149 if (EFI_ERROR (Status)) {\r
150 goto Finish;\r
151 } \r
152\r
153 //\r
154 // 5. Skip over the image checksum (it occupies a single ULONG).\r
155 //\r
156 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
157 //\r
158 // 6. Since there is no Cert Directory in optional header, hash everything\r
159 // from the end of the checksum to the end of image header.\r
160 //\r
161 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
162 //\r
163 // Use PE32 offset.\r
164 //\r
165 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
166 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
167 } else {\r
168 //\r
169 // Use PE32+ offset.\r
170 //\r
171 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
172 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
173 }\r
174\r
175 if (HashSize != 0) {\r
176 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
177 if (EFI_ERROR (Status)) {\r
178 goto Finish;\r
179 }\r
180 } \r
181 } else {\r
182 //\r
183 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
184 //\r
185 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
186 //\r
187 // Use PE32 offset\r
188 //\r
189 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
190 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
191 } else {\r
192 //\r
193 // Use PE32+ offset\r
194 // \r
195 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
196 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
197 }\r
198\r
199 if (HashSize != 0) {\r
200 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
201 if (EFI_ERROR (Status)) {\r
202 goto Finish;\r
203 }\r
204 }\r
205\r
206 //\r
207 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
208 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
209 //\r
210 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
211 //\r
212 // Use PE32 offset\r
213 //\r
214 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
215 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
216 } else {\r
217 //\r
218 // Use PE32+ offset\r
219 //\r
220 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
221 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
222 }\r
223 \r
224 if (HashSize != 0) {\r
225 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
226 if (EFI_ERROR (Status)) {\r
227 goto Finish;\r
228 }\r
229 }\r
230 }\r
231\r
232 //\r
233 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header\r
234 //\r
235 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
236 //\r
237 // Use PE32 offset\r
238 //\r
239 SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
240 } else {\r
241 //\r
242 // Use PE32+ offset\r
243 //\r
244 SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
245 }\r
246\r
247 //\r
248 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
249 // structures in the image. The 'NumberOfSections' field of the image\r
250 // header indicates how big the table should be. Do not include any\r
251 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
252 //\r
253 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
254 if (SectionHeader == NULL) {\r
255 Status = EFI_OUT_OF_RESOURCES;\r
256 goto Finish;\r
257 }\r
258\r
259 //\r
260 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
261 // a key, arrange the elements in the table in ascending order. In other\r
262 // words, sort the section headers according to the disk-file offset of\r
263 // the section.\r
264 //\r
265 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
266 (UINT8 *) (UINTN) ImageAddress +\r
267 PeCoffHeaderOffset +\r
268 sizeof(UINT32) +\r
269 sizeof(EFI_IMAGE_FILE_HEADER) +\r
270 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
271 );\r
272 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
273 Pos = Index;\r
274 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
275 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));\r
276 Pos--;\r
277 }\r
278 CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));\r
279 Section += 1;\r
280 }\r
281\r
282 //\r
283 // 13. Walk through the sorted table, bring the corresponding section\r
284 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
285 // field in the section header to determine the amount of data to hash).\r
286 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
287 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
288 //\r
289 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
290 Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];\r
291 if (Section->SizeOfRawData == 0) {\r
292 continue;\r
293 }\r
294 HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;\r
295 HashSize = (UINTN) Section->SizeOfRawData;\r
296\r
297 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
298 if (EFI_ERROR (Status)) {\r
299 goto Finish;\r
300 }\r
301\r
302 SumOfBytesHashed += HashSize;\r
303 }\r
304\r
305 //\r
306 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
307 // data in the file that needs to be added to the hash. This data begins\r
308 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
309 // FileSize - (CertDirectory->Size)\r
310 //\r
311 if (ImageSize > SumOfBytesHashed) {\r
312 HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
313\r
314 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
315 CertSize = 0;\r
316 } else {\r
317 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
318 //\r
319 // Use PE32 offset.\r
320 //\r
321 CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
322 } else {\r
323 //\r
324 // Use PE32+ offset.\r
325 //\r
326 CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
327 }\r
328 }\r
329\r
330 if (ImageSize > CertSize + SumOfBytesHashed) {\r
331 HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);\r
332\r
333 Status = HashUpdate (HashHandle, HashBase, HashSize);\r
334 if (EFI_ERROR (Status)) {\r
335 goto Finish;\r
336 }\r
337 } else if (ImageSize < CertSize + SumOfBytesHashed) {\r
338 Status = EFI_UNSUPPORTED;\r
339 goto Finish;\r
340 }\r
341 }\r
342\r
343 //\r
344 // 17. Finalize the SHA hash.\r
345 //\r
346 Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);\r
347 if (EFI_ERROR (Status)) {\r
348 goto Finish;\r
349 }\r
350\r
351Finish:\r
352 if (SectionHeader != NULL) {\r
353 FreePool (SectionHeader);\r
354 }\r
355\r
356 return Status;\r
357}\r