VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c

Last change on this file was 105670, checked in by vboxsync, 9 months ago

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

  • Property svn:eol-style set to native
File size: 33.2 KB
Line 
1/** @file
2 The library instance provides security service of TPM measure boot.
3
4 Caution: This file requires additional review when modified.
5 This library will have external input - PE/COFF image and GPT partition.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
10 read is within the image buffer.
11
12 TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
13 data structure within this image buffer before use.
14
15 TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
16 partition data carefully.
17
18Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
19SPDX-License-Identifier: BSD-2-Clause-Patent
20Copyright (c) Microsoft Corporation.<BR>
21
22Copyright (c) Microsoft Corporation.<BR>
23SPDX-License-Identifier: BSD-2-Clause-Patent
24**/
25
26#include <PiDxe.h>
27
28#include <Protocol/TcgService.h>
29#include <Protocol/BlockIo.h>
30#include <Protocol/DiskIo.h>
31#include <Protocol/FirmwareVolumeBlock.h>
32
33#include <Guid/MeasuredFvHob.h>
34
35#include <Library/BaseLib.h>
36#include <Library/DebugLib.h>
37#include <Library/BaseMemoryLib.h>
38#include <Library/MemoryAllocationLib.h>
39#include <Library/DevicePathLib.h>
40#include <Library/UefiBootServicesTableLib.h>
41#include <Library/BaseCryptLib.h>
42#include <Library/PeCoffLib.h>
43#include <Library/SecurityManagementLib.h>
44#include <Library/HobLib.h>
45
46#include "DxeTpmMeasureBootLibSanitization.h"
47
48//
49// Flag to check GPT partition. It only need be measured once.
50//
51BOOLEAN mMeasureGptTableFlag = FALSE;
52UINTN mMeasureGptCount = 0;
53VOID *mFileBuffer;
54UINTN mTpmImageSize;
55//
56// Measured FV handle cache
57//
58EFI_HANDLE mCacheMeasuredHandle = NULL;
59MEASURED_HOB_DATA *mMeasuredHobData = NULL;
60
61/**
62 Reads contents of a PE/COFF image in memory buffer.
63
64 Caution: This function may receive untrusted input.
65 PE/COFF image is external input, so this function will make sure the PE/COFF image content
66 read is within the image buffer.
67
68 @param FileHandle Pointer to the file handle to read the PE/COFF image.
69 @param FileOffset Offset into the PE/COFF image to begin the read operation.
70 @param ReadSize On input, the size in bytes of the requested read operation.
71 On output, the number of bytes actually read.
72 @param Buffer Output buffer that contains the data read from the PE/COFF image.
73
74 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
75**/
76EFI_STATUS
77EFIAPI
78DxeTpmMeasureBootLibImageRead (
79 IN VOID *FileHandle,
80 IN UINTN FileOffset,
81 IN OUT UINTN *ReadSize,
82 OUT VOID *Buffer
83 )
84{
85 UINTN EndPosition;
86
87 if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {
88 return EFI_INVALID_PARAMETER;
89 }
90
91 if (MAX_ADDRESS - FileOffset < *ReadSize) {
92 return EFI_INVALID_PARAMETER;
93 }
94
95 EndPosition = FileOffset + *ReadSize;
96 if (EndPosition > mTpmImageSize) {
97 *ReadSize = (UINT32)(mTpmImageSize - FileOffset);
98 }
99
100 if (FileOffset >= mTpmImageSize) {
101 *ReadSize = 0;
102 }
103
104 CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize);
105
106 return EFI_SUCCESS;
107}
108
109/**
110 Measure GPT table data into TPM log.
111
112 Caution: This function may receive untrusted input.
113 The GPT partition table is external input, so this function should parse partition data carefully.
114
115 @param TcgProtocol Pointer to the located TCG protocol instance.
116 @param GptHandle Handle that GPT partition was installed.
117
118 @retval EFI_SUCCESS Successfully measure GPT table.
119 @retval EFI_UNSUPPORTED Not support GPT table on the given handle.
120 @retval EFI_DEVICE_ERROR Can't get GPT table because device error.
121 @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.
122 @retval other error value
123**/
124EFI_STATUS
125EFIAPI
126TcgMeasureGptTable (
127 IN EFI_TCG_PROTOCOL *TcgProtocol,
128 IN EFI_HANDLE GptHandle
129 )
130{
131 EFI_STATUS Status;
132 EFI_BLOCK_IO_PROTOCOL *BlockIo;
133 EFI_DISK_IO_PROTOCOL *DiskIo;
134 EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
135 EFI_PARTITION_ENTRY *PartitionEntry;
136 UINT8 *EntryPtr;
137 UINTN NumberOfPartition;
138 UINT32 Index;
139 TCG_PCR_EVENT *TcgEvent;
140 EFI_GPT_DATA *GptData;
141 UINT32 EventSize;
142 UINT32 EventNumber;
143 EFI_PHYSICAL_ADDRESS EventLogLastEntry;
144 UINT32 AllocSize;
145
146 GptData = NULL;
147
148 if (mMeasureGptCount > 0) {
149 return EFI_SUCCESS;
150 }
151
152 Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
153 if (EFI_ERROR (Status)) {
154 return EFI_UNSUPPORTED;
155 }
156
157 Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
158 if (EFI_ERROR (Status)) {
159 return EFI_UNSUPPORTED;
160 }
161
162 //
163 // Read the EFI Partition Table Header
164 //
165 PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *)AllocatePool (BlockIo->Media->BlockSize);
166 if (PrimaryHeader == NULL) {
167 return EFI_OUT_OF_RESOURCES;
168 }
169
170 Status = DiskIo->ReadDisk (
171 DiskIo,
172 BlockIo->Media->MediaId,
173 1 * BlockIo->Media->BlockSize,
174 BlockIo->Media->BlockSize,
175 (UINT8 *)PrimaryHeader
176 );
177 if (EFI_ERROR (Status) || EFI_ERROR (TpmSanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
178 DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
179 FreePool (PrimaryHeader);
180 return EFI_DEVICE_ERROR;
181 }
182
183 //
184 // Read the partition entry.
185 //
186 Status = TpmSanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
187 if (EFI_ERROR (Status)) {
188 FreePool (PrimaryHeader);
189 return EFI_DEVICE_ERROR;
190 }
191
192 EntryPtr = (UINT8 *)AllocatePool (AllocSize);
193 if (EntryPtr == NULL) {
194 FreePool (PrimaryHeader);
195 return EFI_OUT_OF_RESOURCES;
196 }
197
198 Status = DiskIo->ReadDisk (
199 DiskIo,
200 BlockIo->Media->MediaId,
201 MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
202 AllocSize,
203 EntryPtr
204 );
205 if (EFI_ERROR (Status)) {
206 FreePool (PrimaryHeader);
207 FreePool (EntryPtr);
208 return EFI_DEVICE_ERROR;
209 }
210
211 //
212 // Count the valid partition
213 //
214 PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;
215 NumberOfPartition = 0;
216 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
217 if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
218 NumberOfPartition++;
219 }
220
221 PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
222 }
223
224 //
225 // Prepare Data for Measurement
226 //
227 Status = TpmSanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize);
228 TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize);
229 if (TcgEvent == NULL) {
230 FreePool (PrimaryHeader);
231 FreePool (EntryPtr);
232 return EFI_OUT_OF_RESOURCES;
233 }
234
235 TcgEvent->PCRIndex = 5;
236 TcgEvent->EventType = EV_EFI_GPT_EVENT;
237 TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR);
238 GptData = (EFI_GPT_DATA *)TcgEvent->Event;
239
240 //
241 // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
242 //
243 CopyMem ((UINT8 *)GptData, (UINT8 *)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
244 GptData->NumberOfPartitions = NumberOfPartition;
245 //
246 // Copy the valid partition entry
247 //
248 PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;
249 NumberOfPartition = 0;
250 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
251 if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
252 CopyMem (
253 (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,
254 (UINT8 *)PartitionEntry,
255 PrimaryHeader->SizeOfPartitionEntry
256 );
257 NumberOfPartition++;
258 }
259
260 PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
261 }
262
263 //
264 // Measure the GPT data
265 //
266 EventNumber = 1;
267 Status = TcgProtocol->HashLogExtendEvent (
268 TcgProtocol,
269 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
270 (UINT64)TcgEvent->EventSize,
271 TPM_ALG_SHA,
272 TcgEvent,
273 &EventNumber,
274 &EventLogLastEntry
275 );
276 if (!EFI_ERROR (Status)) {
277 mMeasureGptCount++;
278 }
279
280 FreePool (PrimaryHeader);
281 FreePool (EntryPtr);
282 FreePool (TcgEvent);
283
284 return Status;
285}
286
287/**
288 Measure PE image into TPM log based on the authenticode image hashing in
289 PE/COFF Specification 8.0 Appendix A.
290
291 Caution: This function may receive untrusted input.
292 PE/COFF image is external input, so this function will validate its data structure
293 within this image buffer before use.
294
295 Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
296 its caller function DxeTpmMeasureBootHandler().
297
298 @param[in] TcgProtocol Pointer to the located TCG protocol instance.
299 @param[in] ImageAddress Start address of image buffer.
300 @param[in] ImageSize Image size
301 @param[in] LinkTimeBase Address that the image is loaded into memory.
302 @param[in] ImageType Image subsystem type.
303 @param[in] FilePath File path is corresponding to the input image.
304
305 @retval EFI_SUCCESS Successfully measure image.
306 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
307 @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
308 @retval other error value
309
310**/
311EFI_STATUS
312EFIAPI
313TcgMeasurePeImage (
314 IN EFI_TCG_PROTOCOL *TcgProtocol,
315 IN EFI_PHYSICAL_ADDRESS ImageAddress,
316 IN UINTN ImageSize,
317 IN UINTN LinkTimeBase,
318 IN UINT16 ImageType,
319 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
320 )
321{
322 EFI_STATUS Status;
323 TCG_PCR_EVENT *TcgEvent;
324 EFI_IMAGE_LOAD_EVENT *ImageLoad;
325 UINT32 FilePathSize;
326 VOID *Sha1Ctx;
327 UINTN CtxSize;
328 EFI_IMAGE_DOS_HEADER *DosHdr;
329 UINT32 PeCoffHeaderOffset;
330 EFI_IMAGE_SECTION_HEADER *Section;
331 UINT8 *HashBase;
332 UINTN HashSize;
333 UINTN SumOfBytesHashed;
334 EFI_IMAGE_SECTION_HEADER *SectionHeader;
335 UINTN Index;
336 UINTN Pos;
337 UINT32 EventSize;
338 UINT32 EventNumber;
339 EFI_PHYSICAL_ADDRESS EventLogLastEntry;
340 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
341 UINT32 NumberOfRvaAndSizes;
342 BOOLEAN HashStatus;
343 UINT32 CertSize;
344
345 Status = EFI_UNSUPPORTED;
346 ImageLoad = NULL;
347 SectionHeader = NULL;
348 Sha1Ctx = NULL;
349 TcgEvent = NULL;
350 FilePathSize = (UINT32)GetDevicePathSize (FilePath);
351
352 // Determine destination PCR by BootPolicy
353 //
354 Status = TpmSanitizePeImageEventSize (FilePathSize, &EventSize);
355 if (EFI_ERROR (Status)) {
356 return EFI_UNSUPPORTED;
357 }
358
359 TcgEvent = AllocateZeroPool (EventSize);
360 if (TcgEvent == NULL) {
361 return EFI_OUT_OF_RESOURCES;
362 }
363
364 TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR);
365 ImageLoad = (EFI_IMAGE_LOAD_EVENT *)TcgEvent->Event;
366
367 switch (ImageType) {
368 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
369 TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;
370 TcgEvent->PCRIndex = 4;
371 break;
372 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
373 TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;
374 TcgEvent->PCRIndex = 2;
375 break;
376 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
377 TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;
378 TcgEvent->PCRIndex = 2;
379 break;
380 default:
381 DEBUG (
382 (
383 DEBUG_ERROR,
384 "TcgMeasurePeImage: Unknown subsystem type %d",
385 ImageType
386 )
387 );
388 goto Finish;
389 }
390
391 ImageLoad->ImageLocationInMemory = ImageAddress;
392 ImageLoad->ImageLengthInMemory = ImageSize;
393 ImageLoad->ImageLinkTimeAddress = LinkTimeBase;
394 ImageLoad->LengthOfDevicePath = FilePathSize;
395 if ((FilePath != NULL) && (FilePathSize != 0)) {
396 CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);
397 }
398
399 //
400 // Check PE/COFF image
401 //
402 DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress;
403 PeCoffHeaderOffset = 0;
404 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
405 PeCoffHeaderOffset = DosHdr->e_lfanew;
406 }
407
408 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset);
409 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
410 goto Finish;
411 }
412
413 //
414 // PE/COFF Image Measurement
415 //
416 // NOTE: The following codes/steps are based upon the authenticode image hashing in
417 // PE/COFF Specification 8.0 Appendix A.
418 //
419 //
420
421 // 1. Load the image header into memory.
422
423 // 2. Initialize a SHA hash context.
424 CtxSize = Sha1GetContextSize ();
425 Sha1Ctx = AllocatePool (CtxSize);
426 if (Sha1Ctx == NULL) {
427 Status = EFI_OUT_OF_RESOURCES;
428 goto Finish;
429 }
430
431 HashStatus = Sha1Init (Sha1Ctx);
432 if (!HashStatus) {
433 goto Finish;
434 }
435
436 //
437 // Measuring PE/COFF Image Header;
438 // But CheckSum field and SECURITY data directory (certificate) are excluded
439 //
440
441 //
442 // 3. Calculate the distance from the base of the image header to the image checksum address.
443 // 4. Hash the image header from its base to beginning of the image checksum.
444 //
445 HashBase = (UINT8 *)(UINTN)ImageAddress;
446 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
447 //
448 // Use PE32 offset
449 //
450 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
451 HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase;
452 } else {
453 //
454 // Use PE32+ offset
455 //
456 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
457 HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase;
458 }
459
460 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
461 if (!HashStatus) {
462 goto Finish;
463 }
464
465 //
466 // 5. Skip over the image checksum (it occupies a single ULONG).
467 //
468 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
469 //
470 // 6. Since there is no Cert Directory in optional header, hash everything
471 // from the end of the checksum to the end of image header.
472 //
473 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
474 //
475 // Use PE32 offset.
476 //
477 HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
478 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
479 } else {
480 //
481 // Use PE32+ offset.
482 //
483 HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
484 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
485 }
486
487 if (HashSize != 0) {
488 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
489 if (!HashStatus) {
490 goto Finish;
491 }
492 }
493 } else {
494 //
495 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
496 //
497 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
498 //
499 // Use PE32 offset
500 //
501 HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
502 HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase;
503 } else {
504 //
505 // Use PE32+ offset
506 //
507 HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
508 HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase;
509 }
510
511 if (HashSize != 0) {
512 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
513 if (!HashStatus) {
514 goto Finish;
515 }
516 }
517
518 //
519 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
520 // 9. Hash everything from the end of the Cert Directory to the end of image header.
521 //
522 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
523 //
524 // Use PE32 offset
525 //
526 HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
527 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
528 } else {
529 //
530 // Use PE32+ offset
531 //
532 HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
533 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
534 }
535
536 if (HashSize != 0) {
537 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
538 if (!HashStatus) {
539 goto Finish;
540 }
541 }
542 }
543
544 //
545 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
546 //
547 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
548 //
549 // Use PE32 offset
550 //
551 SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
552 } else {
553 //
554 // Use PE32+ offset
555 //
556 SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
557 }
558
559 //
560 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
561 // structures in the image. The 'NumberOfSections' field of the image
562 // header indicates how big the table should be. Do not include any
563 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
564 //
565 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
566 if (SectionHeader == NULL) {
567 Status = EFI_OUT_OF_RESOURCES;
568 goto Finish;
569 }
570
571 //
572 // 12. Using the 'PointerToRawData' in the referenced section headers as
573 // a key, arrange the elements in the table in ascending order. In other
574 // words, sort the section headers according to the disk-file offset of
575 // the section.
576 //
577 Section = (EFI_IMAGE_SECTION_HEADER *)(
578 (UINT8 *)(UINTN)ImageAddress +
579 PeCoffHeaderOffset +
580 sizeof (UINT32) +
581 sizeof (EFI_IMAGE_FILE_HEADER) +
582 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
583 );
584 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
585 Pos = Index;
586 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
587 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
588 Pos--;
589 }
590
591 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
592 Section += 1;
593 }
594
595 //
596 // 13. Walk through the sorted table, bring the corresponding section
597 // into memory, and hash the entire section (using the 'SizeOfRawData'
598 // field in the section header to determine the amount of data to hash).
599 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
600 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
601 //
602 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
603 Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index];
604 if (Section->SizeOfRawData == 0) {
605 continue;
606 }
607
608 HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData;
609 HashSize = (UINTN)Section->SizeOfRawData;
610
611 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
612 if (!HashStatus) {
613 goto Finish;
614 }
615
616 SumOfBytesHashed += HashSize;
617 }
618
619 //
620 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
621 // data in the file that needs to be added to the hash. This data begins
622 // at file offset SUM_OF_BYTES_HASHED and its length is:
623 // FileSize - (CertDirectory->Size)
624 //
625 if (ImageSize > SumOfBytesHashed) {
626 HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed;
627
628 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
629 CertSize = 0;
630 } else {
631 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
632 //
633 // Use PE32 offset.
634 //
635 CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
636 } else {
637 //
638 // Use PE32+ offset.
639 //
640 CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
641 }
642 }
643
644 if (ImageSize > CertSize + SumOfBytesHashed) {
645 HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed);
646
647 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
648 if (!HashStatus) {
649 goto Finish;
650 }
651 } else if (ImageSize < CertSize + SumOfBytesHashed) {
652 goto Finish;
653 }
654 }
655
656 //
657 // 17. Finalize the SHA hash.
658 //
659 HashStatus = Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest);
660 if (!HashStatus) {
661 goto Finish;
662 }
663
664 //
665 // Log the PE data
666 //
667 EventNumber = 1;
668 Status = TcgProtocol->HashLogExtendEvent (
669 TcgProtocol,
670 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)NULL,
671 0,
672 TPM_ALG_SHA,
673 TcgEvent,
674 &EventNumber,
675 &EventLogLastEntry
676 );
677 if (Status == EFI_OUT_OF_RESOURCES) {
678 //
679 // Out of resource here means the image is hashed and its result is extended to PCR.
680 // But the event log can't be saved since log area is full.
681 // Just return EFI_SUCCESS in order not to block the image load.
682 //
683 Status = EFI_SUCCESS;
684 }
685
686Finish:
687 FreePool (TcgEvent);
688
689 if (SectionHeader != NULL) {
690 FreePool (SectionHeader);
691 }
692
693 if (Sha1Ctx != NULL ) {
694 FreePool (Sha1Ctx);
695 }
696
697 return Status;
698}
699
700/**
701 The security handler is used to abstract platform-specific policy
702 from the DXE core response to an attempt to use a file that returns a
703 given status for the authentication check from the section extraction protocol.
704
705 The possible responses in a given SAP implementation may include locking
706 flash upon failure to authenticate, attestation logging for all signed drivers,
707 and other exception operations. The File parameter allows for possible logging
708 within the SAP of the driver.
709
710 If the file specified by File with an authentication status specified by
711 AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
712
713 If the file specified by File with an authentication status specified by
714 AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
715 then EFI_ACCESS_DENIED is returned.
716
717 If the file specified by File with an authentication status specified by
718 AuthenticationStatus is not safe for the DXE Core to use right now, but it
719 might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
720 returned.
721
722 If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED.
723
724 @param[in] AuthenticationStatus This is the authentication status returned
725 from the securitymeasurement services for the
726 input file.
727 @param[in] File This is a pointer to the device path of the file that is
728 being dispatched. This will optionally be used for logging.
729 @param[in] FileBuffer File buffer matches the input file device path.
730 @param[in] FileSize Size of File buffer matches the input file device path.
731 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
732
733 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
734 FileBuffer did authenticate, and the platform policy dictates
735 that the DXE Foundation may use the file.
736 @retval other error value
737**/
738EFI_STATUS
739EFIAPI
740DxeTpmMeasureBootHandler (
741 IN UINT32 AuthenticationStatus,
742 IN CONST EFI_DEVICE_PATH_PROTOCOL *File OPTIONAL,
743 IN VOID *FileBuffer,
744 IN UINTN FileSize,
745 IN BOOLEAN BootPolicy
746 )
747{
748 EFI_TCG_PROTOCOL *TcgProtocol;
749 EFI_STATUS Status;
750 TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability;
751 UINT32 TCGFeatureFlags;
752 EFI_PHYSICAL_ADDRESS EventLogLocation;
753 EFI_PHYSICAL_ADDRESS EventLogLastEntry;
754 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
755 EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;
756 EFI_HANDLE Handle;
757 EFI_HANDLE TempHandle;
758 BOOLEAN ApplicationRequired;
759 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
760 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
761 EFI_PHYSICAL_ADDRESS FvAddress;
762 UINT32 Index;
763
764 Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);
765 if (EFI_ERROR (Status)) {
766 //
767 // TCG protocol is not installed. So, TPM is not present.
768 // Don't do any measurement, and directly return EFI_SUCCESS.
769 //
770 return EFI_SUCCESS;
771 }
772
773 ProtocolCapability.Size = (UINT8)sizeof (ProtocolCapability);
774 Status = TcgProtocol->StatusCheck (
775 TcgProtocol,
776 &ProtocolCapability,
777 &TCGFeatureFlags,
778 &EventLogLocation,
779 &EventLogLastEntry
780 );
781 if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag || (!ProtocolCapability.TPMPresentFlag)) {
782 //
783 // TPM device doesn't work or activate.
784 //
785 return EFI_SUCCESS;
786 }
787
788 //
789 // Copy File Device Path
790 //
791 OrigDevicePathNode = DuplicateDevicePath (File);
792
793 //
794 // 1. Check whether this device path support BlockIo protocol.
795 // Is so, this device path may be a GPT device path.
796 //
797 DevicePathNode = OrigDevicePathNode;
798 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);
799 if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {
800 //
801 // Find the gpt partition on the given devicepath
802 //
803 DevicePathNode = OrigDevicePathNode;
804 ASSERT (DevicePathNode != NULL);
805 while (!IsDevicePathEnd (DevicePathNode)) {
806 //
807 // Find the Gpt partition
808 //
809 if ((DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH) &&
810 (DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP))
811 {
812 //
813 // Check whether it is a gpt partition or not
814 //
815 if ((((HARDDRIVE_DEVICE_PATH *)DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) &&
816 (((HARDDRIVE_DEVICE_PATH *)DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID))
817 {
818 //
819 // Change the partition device path to its parent device path (disk) and get the handle.
820 //
821 DevicePathNode->Type = END_DEVICE_PATH_TYPE;
822 DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
823 DevicePathNode = OrigDevicePathNode;
824 Status = gBS->LocateDevicePath (
825 &gEfiDiskIoProtocolGuid,
826 &DevicePathNode,
827 &Handle
828 );
829 if (!EFI_ERROR (Status)) {
830 //
831 // Measure GPT disk.
832 //
833 Status = TcgMeasureGptTable (TcgProtocol, Handle);
834 if (!EFI_ERROR (Status)) {
835 //
836 // GPT disk check done.
837 //
838 mMeasureGptTableFlag = TRUE;
839 }
840 }
841
842 FreePool (OrigDevicePathNode);
843 OrigDevicePathNode = DuplicateDevicePath (File);
844 ASSERT (OrigDevicePathNode != NULL);
845 break;
846 }
847 }
848
849 DevicePathNode = NextDevicePathNode (DevicePathNode);
850 }
851 }
852
853 //
854 // 2. Measure PE image.
855 //
856 ApplicationRequired = FALSE;
857
858 //
859 // Check whether this device path support FVB protocol.
860 //
861 DevicePathNode = OrigDevicePathNode;
862 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle);
863 if (!EFI_ERROR (Status)) {
864 //
865 // Don't check FV image, and directly return EFI_SUCCESS.
866 // It can be extended to the specific FV authentication according to the different requirement.
867 //
868 if (IsDevicePathEnd (DevicePathNode)) {
869 return EFI_SUCCESS;
870 }
871
872 //
873 // The PE image from unmeasured Firmware volume need be measured
874 // The PE image from measured Firmware volume will be measured according to policy below.
875 // If it is driver, do not measure
876 // If it is application, still measure.
877 //
878 ApplicationRequired = TRUE;
879
880 if ((mCacheMeasuredHandle != Handle) && (mMeasuredHobData != NULL)) {
881 //
882 // Search for Root FV of this PE image
883 //
884 TempHandle = Handle;
885 do {
886 Status = gBS->HandleProtocol (
887 TempHandle,
888 &gEfiFirmwareVolumeBlockProtocolGuid,
889 (VOID **)&FvbProtocol
890 );
891 TempHandle = FvbProtocol->ParentHandle;
892 } while (!EFI_ERROR (Status) && FvbProtocol->ParentHandle != NULL);
893
894 //
895 // Search in measured FV Hob
896 //
897 Status = FvbProtocol->GetPhysicalAddress (FvbProtocol, &FvAddress);
898 if (EFI_ERROR (Status)) {
899 return Status;
900 }
901
902 ApplicationRequired = FALSE;
903
904 for (Index = 0; Index < mMeasuredHobData->Num; Index++) {
905 if (mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {
906 //
907 // Cache measured FV for next measurement
908 //
909 mCacheMeasuredHandle = Handle;
910 ApplicationRequired = TRUE;
911 break;
912 }
913 }
914 }
915 }
916
917 //
918 // File is not found.
919 //
920 if (FileBuffer == NULL) {
921 Status = EFI_SECURITY_VIOLATION;
922 goto Finish;
923 }
924
925 mTpmImageSize = FileSize;
926 mFileBuffer = FileBuffer;
927
928 //
929 // Measure PE Image
930 //
931 DevicePathNode = OrigDevicePathNode;
932 ZeroMem (&ImageContext, sizeof (ImageContext));
933 ImageContext.Handle = (VOID *)FileBuffer;
934 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)DxeTpmMeasureBootLibImageRead;
935
936 //
937 // Get information about the image being loaded
938 //
939 Status = PeCoffLoaderGetImageInfo (&ImageContext);
940 if (EFI_ERROR (Status)) {
941 //
942 // Check for invalid parameters.
943 //
944 if (File == NULL) {
945 return EFI_ACCESS_DENIED;
946 }
947
948 //
949 // The information can't be got from the invalid PeImage
950 //
951 goto Finish;
952 }
953
954 //
955 // Measure only application if Application flag is set
956 // Measure drivers and applications if Application flag is not set
957 //
958 if ((!ApplicationRequired) ||
959 (ApplicationRequired && (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)))
960 {
961 //
962 // Print the image path to be measured.
963 //
964 DEBUG_CODE_BEGIN ();
965 CHAR16 *ToText;
966 ToText = ConvertDevicePathToText (
967 DevicePathNode,
968 FALSE,
969 TRUE
970 );
971 if (ToText != NULL) {
972 DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
973 FreePool (ToText);
974 }
975
976 DEBUG_CODE_END ();
977
978 //
979 // Measure PE image into TPM log.
980 //
981 Status = TcgMeasurePeImage (
982 TcgProtocol,
983 (EFI_PHYSICAL_ADDRESS)(UINTN)FileBuffer,
984 FileSize,
985 (UINTN)ImageContext.ImageAddress,
986 ImageContext.ImageType,
987 DevicePathNode
988 );
989 }
990
991 //
992 // Done, free the allocated resource.
993 //
994Finish:
995 if (OrigDevicePathNode != NULL) {
996 FreePool (OrigDevicePathNode);
997 }
998
999 return Status;
1000}
1001
1002/**
1003 Register the security handler to provide TPM measure boot service.
1004
1005 @param ImageHandle ImageHandle of the loaded driver.
1006 @param SystemTable Pointer to the EFI System Table.
1007
1008 @retval EFI_SUCCESS Register successfully.
1009 @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
1010**/
1011EFI_STATUS
1012EFIAPI
1013DxeTpmMeasureBootLibConstructor (
1014 IN EFI_HANDLE ImageHandle,
1015 IN EFI_SYSTEM_TABLE *SystemTable
1016 )
1017{
1018 EFI_HOB_GUID_TYPE *GuidHob;
1019
1020 GuidHob = NULL;
1021
1022 GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);
1023
1024 if (GuidHob != NULL) {
1025 mMeasuredHobData = GET_GUID_HOB_DATA (GuidHob);
1026 }
1027
1028 return RegisterSecurity2Handler (
1029 DxeTpmMeasureBootHandler,
1030 EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
1031 );
1032}
Note: See TracBrowser for help on using the repository browser.

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