VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/Tcg/TdTcg2Dxe/MeasureBootPeCoff.c

最後變更 在這個檔案是 105670,由 vboxsync 提交於 7 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette