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