VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.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: 29.7 KB
Line 
1/** @file
2 The library instance provides security service of TPM2 measure boot and
3 Confidential Computing (CC) measure boot.
4
5 Caution: This file requires additional review when modified.
6 This library will have external input - PE/COFF image and GPT partition.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
9
10 DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
11 read is within the image buffer.
12
13 Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its
14 data structure within this image buffer before use.
15
16 Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
17 partition data carefully.
18
19Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
20(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
21SPDX-License-Identifier: BSD-2-Clause-Patent
22
23Copyright (c) Microsoft Corporation.<BR>
24SPDX-License-Identifier: BSD-2-Clause-Patent
25**/
26
27#include <PiDxe.h>
28
29#include <Protocol/Tcg2Protocol.h>
30#include <Protocol/BlockIo.h>
31#include <Protocol/DiskIo.h>
32#include <Protocol/DevicePathToText.h>
33#include <Protocol/FirmwareVolumeBlock.h>
34
35#include <Guid/MeasuredFvHob.h>
36
37#include <Library/BaseLib.h>
38#include <Library/DebugLib.h>
39#include <Library/BaseMemoryLib.h>
40#include <Library/MemoryAllocationLib.h>
41#include <Library/DevicePathLib.h>
42#include <Library/UefiBootServicesTableLib.h>
43#include <Library/BaseCryptLib.h>
44#include <Library/PeCoffLib.h>
45#include <Library/SecurityManagementLib.h>
46#include <Library/HobLib.h>
47#include <Protocol/CcMeasurement.h>
48
49#include "DxeTpm2MeasureBootLibSanitization.h"
50
51typedef struct {
52 EFI_TCG2_PROTOCOL *Tcg2Protocol;
53 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
54} MEASURE_BOOT_PROTOCOLS;
55
56//
57// Flag to check GPT partition. It only need be measured once.
58//
59BOOLEAN mTcg2MeasureGptTableFlag = FALSE;
60UINTN mTcg2MeasureGptCount = 0;
61VOID *mTcg2FileBuffer;
62UINTN mTcg2ImageSize;
63//
64// Measured FV handle cache
65//
66EFI_HANDLE mTcg2CacheMeasuredHandle = NULL;
67MEASURED_HOB_DATA *mTcg2MeasuredHobData = NULL;
68
69/**
70 Reads contents of a PE/COFF image in memory buffer.
71
72 Caution: This function may receive untrusted input.
73 PE/COFF image is external input, so this function will make sure the PE/COFF image content
74 read is within the image buffer.
75
76 @param FileHandle Pointer to the file handle to read the PE/COFF image.
77 @param FileOffset Offset into the PE/COFF image to begin the read operation.
78 @param ReadSize On input, the size in bytes of the requested read operation.
79 On output, the number of bytes actually read.
80 @param Buffer Output buffer that contains the data read from the PE/COFF image.
81
82 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
83**/
84EFI_STATUS
85EFIAPI
86DxeTpm2MeasureBootLibImageRead (
87 IN VOID *FileHandle,
88 IN UINTN FileOffset,
89 IN OUT UINTN *ReadSize,
90 OUT VOID *Buffer
91 )
92{
93 UINTN EndPosition;
94
95 if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {
96 return EFI_INVALID_PARAMETER;
97 }
98
99 if (MAX_ADDRESS - FileOffset < *ReadSize) {
100 return EFI_INVALID_PARAMETER;
101 }
102
103 EndPosition = FileOffset + *ReadSize;
104 if (EndPosition > mTcg2ImageSize) {
105 *ReadSize = (UINT32)(mTcg2ImageSize - FileOffset);
106 }
107
108 if (FileOffset >= mTcg2ImageSize) {
109 *ReadSize = 0;
110 }
111
112 CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize);
113
114 return EFI_SUCCESS;
115}
116
117/**
118 Measure GPT table data into TPM log.
119
120 Caution: This function may receive untrusted input.
121 The GPT partition table is external input, so this function should parse partition data carefully.
122
123 @param MeasureBootProtocols Pointer to the located MeasureBoot protocol instances (i.e. TCG2/CC protocol).
124 @param GptHandle Handle that GPT partition was installed.
125
126 @retval EFI_SUCCESS Successfully measure GPT table.
127 @retval EFI_UNSUPPORTED Not support GPT table on the given handle.
128 @retval EFI_DEVICE_ERROR Can't get GPT table because device error.
129 @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.
130 @retval other error value
131**/
132EFI_STATUS
133EFIAPI
134Tcg2MeasureGptTable (
135 IN MEASURE_BOOT_PROTOCOLS *MeasureBootProtocols,
136 IN EFI_HANDLE GptHandle
137 )
138{
139 EFI_STATUS Status;
140 EFI_BLOCK_IO_PROTOCOL *BlockIo;
141 EFI_DISK_IO_PROTOCOL *DiskIo;
142 EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
143 EFI_PARTITION_ENTRY *PartitionEntry;
144 UINT8 *EntryPtr;
145 UINTN NumberOfPartition;
146 UINT32 Index;
147 UINT8 *EventPtr;
148 EFI_TCG2_EVENT *Tcg2Event;
149 EFI_CC_EVENT *CcEvent;
150 EFI_GPT_DATA *GptData;
151 UINT32 TcgEventSize;
152 EFI_TCG2_PROTOCOL *Tcg2Protocol;
153 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
154 EFI_CC_MR_INDEX MrIndex;
155 UINT32 AllocSize;
156
157 if (mTcg2MeasureGptCount > 0) {
158 return EFI_SUCCESS;
159 }
160
161 PrimaryHeader = NULL;
162 EntryPtr = NULL;
163 EventPtr = NULL;
164
165 Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol;
166 CcProtocol = MeasureBootProtocols->CcProtocol;
167
168 if ((Tcg2Protocol == NULL) && (CcProtocol == NULL)) {
169 ASSERT (FALSE);
170 return EFI_UNSUPPORTED;
171 }
172
173 if (sizeof (EFI_CC_EVENT) != sizeof (EFI_TCG2_EVENT)) {
174 ASSERT (FALSE);
175 return EFI_UNSUPPORTED;
176 }
177
178 Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
179 if (EFI_ERROR (Status)) {
180 return EFI_UNSUPPORTED;
181 }
182
183 Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);
184 if (EFI_ERROR (Status)) {
185 return EFI_UNSUPPORTED;
186 }
187
188 //
189 // Read the EFI Partition Table Header
190 //
191 PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *)AllocatePool (BlockIo->Media->BlockSize);
192 if (PrimaryHeader == NULL) {
193 return EFI_OUT_OF_RESOURCES;
194 }
195
196 Status = DiskIo->ReadDisk (
197 DiskIo,
198 BlockIo->Media->MediaId,
199 1 * BlockIo->Media->BlockSize,
200 BlockIo->Media->BlockSize,
201 (UINT8 *)PrimaryHeader
202 );
203 if (EFI_ERROR (Status) || EFI_ERROR (Tpm2SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
204 DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
205 FreePool (PrimaryHeader);
206 return EFI_DEVICE_ERROR;
207 }
208
209 //
210 // Read the partition entry.
211 //
212 Status = Tpm2SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
213 if (EFI_ERROR (Status)) {
214 FreePool (PrimaryHeader);
215 return EFI_BAD_BUFFER_SIZE;
216 }
217
218 EntryPtr = (UINT8 *)AllocatePool (AllocSize);
219 if (EntryPtr == NULL) {
220 FreePool (PrimaryHeader);
221 return EFI_OUT_OF_RESOURCES;
222 }
223
224 Status = DiskIo->ReadDisk (
225 DiskIo,
226 BlockIo->Media->MediaId,
227 MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
228 AllocSize,
229 EntryPtr
230 );
231 if (EFI_ERROR (Status)) {
232 FreePool (PrimaryHeader);
233 FreePool (EntryPtr);
234 return EFI_DEVICE_ERROR;
235 }
236
237 //
238 // Count the valid partition
239 //
240 PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;
241 NumberOfPartition = 0;
242 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
243 if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
244 NumberOfPartition++;
245 }
246
247 PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
248 }
249
250 //
251 // Prepare Data for Measurement (CcProtocol and Tcg2Protocol)
252 //
253 Status = Tpm2SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize);
254 if (EFI_ERROR (Status)) {
255 FreePool (PrimaryHeader);
256 FreePool (EntryPtr);
257 return EFI_DEVICE_ERROR;
258 }
259
260 EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize);
261 if (EventPtr == NULL) {
262 Status = EFI_OUT_OF_RESOURCES;
263 goto Exit;
264 }
265
266 Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;
267 Tcg2Event->Size = TcgEventSize;
268 Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
269 Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
270 Tcg2Event->Header.PCRIndex = 5;
271 Tcg2Event->Header.EventType = EV_EFI_GPT_EVENT;
272 GptData = (EFI_GPT_DATA *)Tcg2Event->Event;
273
274 //
275 // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
276 //
277 CopyMem ((UINT8 *)GptData, (UINT8 *)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
278 GptData->NumberOfPartitions = NumberOfPartition;
279 //
280 // Copy the valid partition entry
281 //
282 PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;
283 NumberOfPartition = 0;
284 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
285 if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
286 CopyMem (
287 (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,
288 (UINT8 *)PartitionEntry,
289 PrimaryHeader->SizeOfPartitionEntry
290 );
291 NumberOfPartition++;
292 }
293
294 PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
295 }
296
297 //
298 // Only one of TCG2_PROTOCOL or CC_MEASUREMENT_PROTOCOL is exposed.
299 // So Measure the GPT data with one of the protocol.
300 //
301 if (CcProtocol != NULL) {
302 //
303 // EFI_CC_EVENT share the same data structure with EFI_TCG2_EVENT
304 // except the MrIndex and PCRIndex in Header.
305 // Tcg2Event has been created and initialized before. So only the MrIndex need
306 // be adjusted.
307 //
308 Status = CcProtocol->MapPcrToMrIndex (CcProtocol, Tcg2Event->Header.PCRIndex, &MrIndex);
309 if (EFI_ERROR (Status)) {
310 DEBUG ((DEBUG_ERROR, "Cannot map PcrIndex(%d) to MrIndex\n", Tcg2Event->Header.PCRIndex));
311 goto Exit;
312 }
313
314 CcEvent = (EFI_CC_EVENT *)EventPtr;
315 CcEvent->Header.MrIndex = MrIndex;
316 Status = CcProtocol->HashLogExtendEvent (
317 CcProtocol,
318 0,
319 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
320 (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
321 CcEvent
322 );
323 if (!EFI_ERROR (Status)) {
324 mTcg2MeasureGptCount++;
325 }
326
327 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Cc MeasureGptTable - %r\n", Status));
328 } else if (Tcg2Protocol != NULL) {
329 //
330 // If Tcg2Protocol is installed, then Measure GPT data with this protocol.
331 //
332 Status = Tcg2Protocol->HashLogExtendEvent (
333 Tcg2Protocol,
334 0,
335 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
336 (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
337 Tcg2Event
338 );
339 if (!EFI_ERROR (Status)) {
340 mTcg2MeasureGptCount++;
341 }
342
343 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Tcg2 MeasureGptTable - %r\n", Status));
344 }
345
346Exit:
347 if (PrimaryHeader != NULL) {
348 FreePool (PrimaryHeader);
349 }
350
351 if (EntryPtr != NULL) {
352 FreePool (EntryPtr);
353 }
354
355 if (EventPtr != NULL) {
356 FreePool (EventPtr);
357 }
358
359 return Status;
360}
361
362/**
363 Measure PE image into TPM log based on the authenticode image hashing in
364 PE/COFF Specification 8.0 Appendix A.
365
366 Caution: This function may receive untrusted input.
367 PE/COFF image is external input, so this function will validate its data structure
368 within this image buffer before use.
369
370 @param[in] MeasureBootProtocols Pointer to the located MeasureBoot protocol instances.
371 @param[in] ImageAddress Start address of image buffer.
372 @param[in] ImageSize Image size
373 @param[in] LinkTimeBase Address that the image is loaded into memory.
374 @param[in] ImageType Image subsystem type.
375 @param[in] FilePath File path is corresponding to the input image.
376
377 @retval EFI_SUCCESS Successfully measure image.
378 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
379 @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
380 @retval other error value
381**/
382EFI_STATUS
383EFIAPI
384Tcg2MeasurePeImage (
385 IN MEASURE_BOOT_PROTOCOLS *MeasureBootProtocols,
386 IN EFI_PHYSICAL_ADDRESS ImageAddress,
387 IN UINTN ImageSize,
388 IN UINTN LinkTimeBase,
389 IN UINT16 ImageType,
390 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
391 )
392{
393 EFI_STATUS Status;
394 EFI_TCG2_EVENT *Tcg2Event;
395 EFI_IMAGE_LOAD_EVENT *ImageLoad;
396 UINT32 FilePathSize;
397 UINT32 EventSize;
398 EFI_CC_EVENT *CcEvent;
399 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
400 EFI_TCG2_PROTOCOL *Tcg2Protocol;
401 UINT8 *EventPtr;
402 EFI_CC_MR_INDEX MrIndex;
403
404 Status = EFI_UNSUPPORTED;
405 ImageLoad = NULL;
406 EventPtr = NULL;
407 Tcg2Event = NULL;
408
409 Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol;
410 CcProtocol = MeasureBootProtocols->CcProtocol;
411
412 if ((Tcg2Protocol == NULL) && (CcProtocol == NULL)) {
413 ASSERT (FALSE);
414 return EFI_UNSUPPORTED;
415 }
416
417 if (sizeof (EFI_CC_EVENT) != sizeof (EFI_TCG2_EVENT)) {
418 ASSERT (FALSE);
419 return EFI_UNSUPPORTED;
420 }
421
422 FilePathSize = (UINT32)GetDevicePathSize (FilePath);
423 Status = Tpm2SanitizePeImageEventSize (FilePathSize, &EventSize);
424 if (EFI_ERROR (Status)) {
425 return EFI_UNSUPPORTED;
426 }
427
428 //
429 // Determine destination PCR by BootPolicy
430 //
431 // from a malicious GPT disk partition
432 EventPtr = AllocateZeroPool (EventSize);
433 if (EventPtr == NULL) {
434 return EFI_OUT_OF_RESOURCES;
435 }
436
437 Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;
438 Tcg2Event->Size = EventSize;
439 Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
440 Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
441 ImageLoad = (EFI_IMAGE_LOAD_EVENT *)Tcg2Event->Event;
442
443 switch (ImageType) {
444 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
445 Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_APPLICATION;
446 Tcg2Event->Header.PCRIndex = 4;
447 break;
448 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
449 Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_DRIVER;
450 Tcg2Event->Header.PCRIndex = 2;
451 break;
452 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
453 Tcg2Event->Header.EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;
454 Tcg2Event->Header.PCRIndex = 2;
455 break;
456 default:
457 DEBUG (
458 (
459 DEBUG_ERROR,
460 "Tcg2MeasurePeImage: Unknown subsystem type %d",
461 ImageType
462 )
463 );
464 goto Finish;
465 }
466
467 ImageLoad->ImageLocationInMemory = ImageAddress;
468 ImageLoad->ImageLengthInMemory = ImageSize;
469 ImageLoad->ImageLinkTimeAddress = LinkTimeBase;
470 ImageLoad->LengthOfDevicePath = FilePathSize;
471 if ((FilePath != NULL) && (FilePathSize != 0)) {
472 CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);
473 }
474
475 //
476 // Log the PE data
477 //
478 if (CcProtocol != NULL) {
479 Status = CcProtocol->MapPcrToMrIndex (CcProtocol, Tcg2Event->Header.PCRIndex, &MrIndex);
480 if (EFI_ERROR (Status)) {
481 DEBUG ((DEBUG_ERROR, "Cannot map PcrIndex(%d) to MrIndex\n", Tcg2Event->Header.PCRIndex));
482 goto Finish;
483 }
484
485 CcEvent = (EFI_CC_EVENT *)EventPtr;
486 CcEvent->Header.MrIndex = MrIndex;
487
488 Status = CcProtocol->HashLogExtendEvent (
489 CcProtocol,
490 PE_COFF_IMAGE,
491 ImageAddress,
492 ImageSize,
493 CcEvent
494 );
495 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Cc MeasurePeImage - %r\n", Status));
496 } else if (Tcg2Protocol != NULL) {
497 Status = Tcg2Protocol->HashLogExtendEvent (
498 Tcg2Protocol,
499 PE_COFF_IMAGE,
500 ImageAddress,
501 ImageSize,
502 Tcg2Event
503 );
504 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Tcg2 MeasurePeImage - %r\n", Status));
505 }
506
507 if (Status == EFI_VOLUME_FULL) {
508 //
509 // Volume full here means the image is hashed and its result is extended to PCR.
510 // But the event log can't be saved since log area is full.
511 // Just return EFI_SUCCESS in order not to block the image load.
512 //
513 Status = EFI_SUCCESS;
514 }
515
516Finish:
517 if (EventPtr != NULL) {
518 FreePool (EventPtr);
519 }
520
521 return Status;
522}
523
524/**
525 Get the measure boot protocols.
526
527 There are 2 measure boot, TCG2 protocol based and Cc measurement protocol based.
528
529 @param MeasureBootProtocols Pointer to the located measure boot protocol instances.
530
531 @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance).
532 @retval EFI_UNSUPPORTED Measure boot is not supported.
533**/
534EFI_STATUS
535EFIAPI
536GetMeasureBootProtocols (
537 MEASURE_BOOT_PROTOCOLS *MeasureBootProtocols
538 )
539{
540 EFI_STATUS Status;
541 EFI_TCG2_PROTOCOL *Tcg2Protocol;
542 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
543 EFI_TCG2_BOOT_SERVICE_CAPABILITY Tcg2ProtocolCapability;
544 EFI_CC_BOOT_SERVICE_CAPABILITY CcProtocolCapability;
545
546 CcProtocol = NULL;
547 Status = gBS->LocateProtocol (&gEfiCcMeasurementProtocolGuid, NULL, (VOID **)&CcProtocol);
548 if (EFI_ERROR (Status)) {
549 //
550 // Cc Measurement protocol is not installed.
551 //
552 DEBUG ((DEBUG_VERBOSE, "CcMeasurementProtocol is not installed. - %r\n", Status));
553 } else {
554 ZeroMem (&CcProtocolCapability, sizeof (CcProtocolCapability));
555 CcProtocolCapability.Size = sizeof (CcProtocolCapability);
556 Status = CcProtocol->GetCapability (CcProtocol, &CcProtocolCapability);
557 if (EFI_ERROR (Status) || (CcProtocolCapability.CcType.Type == EFI_CC_TYPE_NONE)) {
558 DEBUG ((DEBUG_ERROR, " CcProtocol->GetCapability returns : %x, %r\n", CcProtocolCapability.CcType.Type, Status));
559 CcProtocol = NULL;
560 }
561 }
562
563 Tcg2Protocol = NULL;
564 Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **)&Tcg2Protocol);
565 if (EFI_ERROR (Status)) {
566 //
567 // Tcg2 protocol is not installed. So, TPM2 is not present.
568 //
569 DEBUG ((DEBUG_VERBOSE, "Tcg2Protocol is not installed. - %r\n", Status));
570 } else {
571 Tcg2ProtocolCapability.Size = (UINT8)sizeof (Tcg2ProtocolCapability);
572 Status = Tcg2Protocol->GetCapability (Tcg2Protocol, &Tcg2ProtocolCapability);
573 if (EFI_ERROR (Status) || (!Tcg2ProtocolCapability.TPMPresentFlag)) {
574 //
575 // TPM device doesn't work or activate.
576 //
577 DEBUG ((DEBUG_ERROR, "TPMPresentFlag=FALSE %r\n", Status));
578 Tcg2Protocol = NULL;
579 }
580 }
581
582 MeasureBootProtocols->Tcg2Protocol = Tcg2Protocol;
583 MeasureBootProtocols->CcProtocol = CcProtocol;
584
585 return (Tcg2Protocol == NULL && CcProtocol == NULL) ? EFI_UNSUPPORTED : EFI_SUCCESS;
586}
587
588/**
589 The security handler is used to abstract platform-specific policy
590 from the DXE core response to an attempt to use a file that returns a
591 given status for the authentication check from the section extraction protocol.
592
593 The possible responses in a given SAP implementation may include locking
594 flash upon failure to authenticate, attestation logging for all signed drivers,
595 and other exception operations. The File parameter allows for possible logging
596 within the SAP of the driver.
597
598 If the file specified by File with an authentication status specified by
599 AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
600
601 If the file specified by File with an authentication status specified by
602 AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
603 then EFI_ACCESS_DENIED is returned.
604
605 If the file specified by File with an authentication status specified by
606 AuthenticationStatus is not safe for the DXE Core to use right now, but it
607 might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
608 returned.
609
610 If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED.
611
612 @param[in] AuthenticationStatus This is the authentication status returned
613 from the securitymeasurement services for the
614 input file.
615 @param[in] File This is a pointer to the device path of the file that is
616 being dispatched. This will optionally be used for logging.
617 @param[in] FileBuffer File buffer matches the input file device path.
618 @param[in] FileSize Size of File buffer matches the input file device path.
619 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
620
621 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
622 FileBuffer did authenticate, and the platform policy dictates
623 that the DXE Foundation may use the file.
624 @retval other error value
625**/
626EFI_STATUS
627EFIAPI
628DxeTpm2MeasureBootHandler (
629 IN UINT32 AuthenticationStatus,
630 IN CONST EFI_DEVICE_PATH_PROTOCOL *File OPTIONAL,
631 IN VOID *FileBuffer,
632 IN UINTN FileSize,
633 IN BOOLEAN BootPolicy
634 )
635{
636 MEASURE_BOOT_PROTOCOLS MeasureBootProtocols;
637 EFI_STATUS Status;
638 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
639 EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;
640 EFI_HANDLE Handle;
641 EFI_HANDLE TempHandle;
642 BOOLEAN ApplicationRequired;
643 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
644 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
645 EFI_PHYSICAL_ADDRESS FvAddress;
646 UINT32 Index;
647
648 MeasureBootProtocols.Tcg2Protocol = NULL;
649 MeasureBootProtocols.CcProtocol = NULL;
650
651 Status = GetMeasureBootProtocols (&MeasureBootProtocols);
652
653 if (EFI_ERROR (Status)) {
654 //
655 // None of Measured boot protocols (Tcg2, Cc) is installed.
656 // Don't do any measurement, and directly return EFI_SUCCESS.
657 //
658 DEBUG ((DEBUG_INFO, "None of Tcg2Protocol/CcMeasurementProtocol is installed.\n"));
659 return EFI_SUCCESS;
660 }
661
662 DEBUG (
663 (
664 DEBUG_INFO,
665 "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
666 MeasureBootProtocols.Tcg2Protocol,
667 MeasureBootProtocols.CcProtocol
668 )
669 );
670
671 //
672 // Copy File Device Path
673 //
674 OrigDevicePathNode = DuplicateDevicePath (File);
675
676 //
677 // 1. Check whether this device path support BlockIo protocol.
678 // Is so, this device path may be a GPT device path.
679 //
680 DevicePathNode = OrigDevicePathNode;
681 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);
682 if (!EFI_ERROR (Status) && !mTcg2MeasureGptTableFlag) {
683 //
684 // Find the gpt partition on the given devicepath
685 //
686 DevicePathNode = OrigDevicePathNode;
687 ASSERT (DevicePathNode != NULL);
688 while (!IsDevicePathEnd (DevicePathNode)) {
689 //
690 // Find the Gpt partition
691 //
692 if ((DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH) &&
693 (DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP))
694 {
695 //
696 // Check whether it is a gpt partition or not
697 //
698 if ((((HARDDRIVE_DEVICE_PATH *)DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) &&
699 (((HARDDRIVE_DEVICE_PATH *)DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID))
700 {
701 //
702 // Change the partition device path to its parent device path (disk) and get the handle.
703 //
704 DevicePathNode->Type = END_DEVICE_PATH_TYPE;
705 DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
706 DevicePathNode = OrigDevicePathNode;
707 Status = gBS->LocateDevicePath (
708 &gEfiDiskIoProtocolGuid,
709 &DevicePathNode,
710 &Handle
711 );
712 if (!EFI_ERROR (Status)) {
713 //
714 // Measure GPT disk.
715 //
716 Status = Tcg2MeasureGptTable (&MeasureBootProtocols, Handle);
717
718 if (!EFI_ERROR (Status)) {
719 //
720 // GPT disk check done.
721 //
722 mTcg2MeasureGptTableFlag = TRUE;
723 }
724 }
725
726 FreePool (OrigDevicePathNode);
727 OrigDevicePathNode = DuplicateDevicePath (File);
728 ASSERT (OrigDevicePathNode != NULL);
729 break;
730 }
731 }
732
733 DevicePathNode = NextDevicePathNode (DevicePathNode);
734 }
735 }
736
737 //
738 // 2. Measure PE image.
739 //
740 ApplicationRequired = FALSE;
741
742 //
743 // Check whether this device path support FVB protocol.
744 //
745 DevicePathNode = OrigDevicePathNode;
746 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle);
747 if (!EFI_ERROR (Status)) {
748 //
749 // Don't check FV image, and directly return EFI_SUCCESS.
750 // It can be extended to the specific FV authentication according to the different requirement.
751 //
752 if (IsDevicePathEnd (DevicePathNode)) {
753 return EFI_SUCCESS;
754 }
755
756 //
757 // The PE image from unmeasured Firmware volume need be measured
758 // The PE image from measured Firmware volume will be measured according to policy below.
759 // If it is driver, do not measure
760 // If it is application, still measure.
761 //
762 ApplicationRequired = TRUE;
763
764 if ((mTcg2CacheMeasuredHandle != Handle) && (mTcg2MeasuredHobData != NULL)) {
765 //
766 // Search for Root FV of this PE image
767 //
768 TempHandle = Handle;
769 do {
770 Status = gBS->HandleProtocol (
771 TempHandle,
772 &gEfiFirmwareVolumeBlockProtocolGuid,
773 (VOID **)&FvbProtocol
774 );
775 TempHandle = FvbProtocol->ParentHandle;
776 } while (!EFI_ERROR (Status) && FvbProtocol->ParentHandle != NULL);
777
778 //
779 // Search in measured FV Hob
780 //
781 Status = FvbProtocol->GetPhysicalAddress (FvbProtocol, &FvAddress);
782 if (EFI_ERROR (Status)) {
783 return Status;
784 }
785
786 ApplicationRequired = FALSE;
787
788 for (Index = 0; Index < mTcg2MeasuredHobData->Num; Index++) {
789 if (mTcg2MeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {
790 //
791 // Cache measured FV for next measurement
792 //
793 mTcg2CacheMeasuredHandle = Handle;
794 ApplicationRequired = TRUE;
795 break;
796 }
797 }
798 }
799 }
800
801 //
802 // File is not found.
803 //
804 if (FileBuffer == NULL) {
805 Status = EFI_SECURITY_VIOLATION;
806 goto Finish;
807 }
808
809 mTcg2ImageSize = FileSize;
810 mTcg2FileBuffer = FileBuffer;
811
812 //
813 // Measure PE Image
814 //
815 DevicePathNode = OrigDevicePathNode;
816 ZeroMem (&ImageContext, sizeof (ImageContext));
817 ImageContext.Handle = (VOID *)FileBuffer;
818 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)DxeTpm2MeasureBootLibImageRead;
819
820 //
821 // Get information about the image being loaded
822 //
823 Status = PeCoffLoaderGetImageInfo (&ImageContext);
824 if (EFI_ERROR (Status)) {
825 //
826 // Check for invalid parameters.
827 //
828 if (File == NULL) {
829 Status = EFI_ACCESS_DENIED;
830 }
831
832 //
833 // The information can't be got from the invalid PeImage
834 //
835 goto Finish;
836 }
837
838 //
839 // Measure only application if Application flag is set
840 // Measure drivers and applications if Application flag is not set
841 //
842 if ((!ApplicationRequired) ||
843 (ApplicationRequired && (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)))
844 {
845 //
846 // Print the image path to be measured.
847 //
848 DEBUG_CODE_BEGIN ();
849 CHAR16 *ToText;
850 ToText = ConvertDevicePathToText (
851 DevicePathNode,
852 FALSE,
853 TRUE
854 );
855 if (ToText != NULL) {
856 DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
857 FreePool (ToText);
858 }
859
860 DEBUG_CODE_END ();
861
862 //
863 // Measure PE image into TPM log.
864 //
865 Status = Tcg2MeasurePeImage (
866 &MeasureBootProtocols,
867 (EFI_PHYSICAL_ADDRESS)(UINTN)FileBuffer,
868 FileSize,
869 (UINTN)ImageContext.ImageAddress,
870 ImageContext.ImageType,
871 DevicePathNode
872 );
873 }
874
875 //
876 // Done, free the allocated resource.
877 //
878Finish:
879 if (OrigDevicePathNode != NULL) {
880 FreePool (OrigDevicePathNode);
881 }
882
883 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - %r\n", Status));
884
885 return Status;
886}
887
888/**
889 Register the security handler to provide TPM measure boot service.
890
891 @param ImageHandle ImageHandle of the loaded driver.
892 @param SystemTable Pointer to the EFI System Table.
893
894 @retval EFI_SUCCESS Register successfully.
895 @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
896**/
897EFI_STATUS
898EFIAPI
899DxeTpm2MeasureBootLibConstructor (
900 IN EFI_HANDLE ImageHandle,
901 IN EFI_SYSTEM_TABLE *SystemTable
902 )
903{
904 EFI_HOB_GUID_TYPE *GuidHob;
905
906 GuidHob = NULL;
907
908 GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);
909
910 if (GuidHob != NULL) {
911 mTcg2MeasuredHobData = GET_GUID_HOB_DATA (GuidHob);
912 }
913
914 return RegisterSecurity2Handler (
915 DxeTpm2MeasureBootHandler,
916 EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
917 );
918}
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