123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990 |
- /** @file
- The library instance provides security service of TPM measure boot.
- Caution: This file requires additional review when modified.
- This library will have external input - PE/COFF image and GPT partition.
- This external input must be validated carefully to avoid security issue like
- buffer overflow, integer overflow.
- DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
- read is within the image buffer.
- TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
- data structure within this image buffer before use.
- TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
- partition data carefully.
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <PiDxe.h>
- #include <Protocol/TcgService.h>
- #include <Protocol/BlockIo.h>
- #include <Protocol/DiskIo.h>
- #include <Protocol/FirmwareVolumeBlock.h>
- #include <Guid/MeasuredFvHob.h>
- #include <Library/BaseLib.h>
- #include <Library/DebugLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/DevicePathLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/BaseCryptLib.h>
- #include <Library/PeCoffLib.h>
- #include <Library/SecurityManagementLib.h>
- #include <Library/HobLib.h>
- //
- // Flag to check GPT partition. It only need be measured once.
- //
- BOOLEAN mMeasureGptTableFlag = FALSE;
- UINTN mMeasureGptCount = 0;
- VOID *mFileBuffer;
- UINTN mTpmImageSize;
- //
- // Measured FV handle cache
- //
- EFI_HANDLE mCacheMeasuredHandle = NULL;
- MEASURED_HOB_DATA *mMeasuredHobData = NULL;
- /**
- Reads contents of a PE/COFF image in memory buffer.
- Caution: This function may receive untrusted input.
- PE/COFF image is external input, so this function will make sure the PE/COFF image content
- read is within the image buffer.
- @param FileHandle Pointer to the file handle to read the PE/COFF image.
- @param FileOffset Offset into the PE/COFF image to begin the read operation.
- @param ReadSize On input, the size in bytes of the requested read operation.
- On output, the number of bytes actually read.
- @param Buffer Output buffer that contains the data read from the PE/COFF image.
- @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
- **/
- EFI_STATUS
- EFIAPI
- DxeTpmMeasureBootLibImageRead (
- IN VOID *FileHandle,
- IN UINTN FileOffset,
- IN OUT UINTN *ReadSize,
- OUT VOID *Buffer
- )
- {
- UINTN EndPosition;
- if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (MAX_ADDRESS - FileOffset < *ReadSize) {
- return EFI_INVALID_PARAMETER;
- }
- EndPosition = FileOffset + *ReadSize;
- if (EndPosition > mTpmImageSize) {
- *ReadSize = (UINT32)(mTpmImageSize - FileOffset);
- }
- if (FileOffset >= mTpmImageSize) {
- *ReadSize = 0;
- }
- CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
- return EFI_SUCCESS;
- }
- /**
- Measure GPT table data into TPM log.
- Caution: This function may receive untrusted input.
- The GPT partition table is external input, so this function should parse partition data carefully.
- @param TcgProtocol Pointer to the located TCG protocol instance.
- @param GptHandle Handle that GPT partition was installed.
- @retval EFI_SUCCESS Successfully measure GPT table.
- @retval EFI_UNSUPPORTED Not support GPT table on the given handle.
- @retval EFI_DEVICE_ERROR Can't get GPT table because device error.
- @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.
- @retval other error value
- **/
- EFI_STATUS
- EFIAPI
- TcgMeasureGptTable (
- IN EFI_TCG_PROTOCOL *TcgProtocol,
- IN EFI_HANDLE GptHandle
- )
- {
- EFI_STATUS Status;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- EFI_DISK_IO_PROTOCOL *DiskIo;
- EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
- EFI_PARTITION_ENTRY *PartitionEntry;
- UINT8 *EntryPtr;
- UINTN NumberOfPartition;
- UINT32 Index;
- TCG_PCR_EVENT *TcgEvent;
- EFI_GPT_DATA *GptData;
- UINT32 EventSize;
- UINT32 EventNumber;
- EFI_PHYSICAL_ADDRESS EventLogLastEntry;
- if (mMeasureGptCount > 0) {
- return EFI_SUCCESS;
- }
- Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo);
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
- Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo);
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
- //
- // Read the EFI Partition Table Header
- //
- PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize);
- if (PrimaryHeader == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- 1 * BlockIo->Media->BlockSize,
- BlockIo->Media->BlockSize,
- (UINT8 *)PrimaryHeader
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n"));
- FreePool (PrimaryHeader);
- return EFI_DEVICE_ERROR;
- }
- //
- // Read the partition entry.
- //
- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
- if (EntryPtr == NULL) {
- FreePool (PrimaryHeader);
- return EFI_OUT_OF_RESOURCES;
- }
- Status = DiskIo->ReadDisk (
- DiskIo,
- BlockIo->Media->MediaId,
- MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
- EntryPtr
- );
- if (EFI_ERROR (Status)) {
- FreePool (PrimaryHeader);
- FreePool (EntryPtr);
- return EFI_DEVICE_ERROR;
- }
- //
- // Count the valid partition
- //
- PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;
- NumberOfPartition = 0;
- for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
- if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
- NumberOfPartition++;
- }
- PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
- }
- //
- // Prepare Data for Measurement
- //
- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
- TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));
- if (TcgEvent == NULL) {
- FreePool (PrimaryHeader);
- FreePool (EntryPtr);
- return EFI_OUT_OF_RESOURCES;
- }
- TcgEvent->PCRIndex = 5;
- TcgEvent->EventType = EV_EFI_GPT_EVENT;
- TcgEvent->EventSize = EventSize;
- GptData = (EFI_GPT_DATA *) TcgEvent->Event;
- //
- // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
- //
- CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
- GptData->NumberOfPartitions = NumberOfPartition;
- //
- // Copy the valid partition entry
- //
- PartitionEntry = (EFI_PARTITION_ENTRY*)EntryPtr;
- NumberOfPartition = 0;
- for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
- if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
- CopyMem (
- (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,
- (UINT8 *)PartitionEntry,
- PrimaryHeader->SizeOfPartitionEntry
- );
- NumberOfPartition++;
- }
- PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
- }
- //
- // Measure the GPT data
- //
- EventNumber = 1;
- Status = TcgProtocol->HashLogExtendEvent (
- TcgProtocol,
- (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,
- (UINT64) TcgEvent->EventSize,
- TPM_ALG_SHA,
- TcgEvent,
- &EventNumber,
- &EventLogLastEntry
- );
- if (!EFI_ERROR (Status)) {
- mMeasureGptCount++;
- }
- FreePool (PrimaryHeader);
- FreePool (EntryPtr);
- FreePool (TcgEvent);
- return Status;
- }
- /**
- Measure PE image into TPM log based on the authenticode image hashing in
- PE/COFF Specification 8.0 Appendix A.
- Caution: This function may receive untrusted input.
- PE/COFF image is external input, so this function will validate its data structure
- within this image buffer before use.
- Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
- its caller function DxeTpmMeasureBootHandler().
- @param[in] TcgProtocol Pointer to the located TCG protocol instance.
- @param[in] ImageAddress Start address of image buffer.
- @param[in] ImageSize Image size
- @param[in] LinkTimeBase Address that the image is loaded into memory.
- @param[in] ImageType Image subsystem type.
- @param[in] FilePath File path is corresponding to the input image.
- @retval EFI_SUCCESS Successfully measure image.
- @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
- @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
- @retval other error value
- **/
- EFI_STATUS
- EFIAPI
- TcgMeasurePeImage (
- IN EFI_TCG_PROTOCOL *TcgProtocol,
- IN EFI_PHYSICAL_ADDRESS ImageAddress,
- IN UINTN ImageSize,
- IN UINTN LinkTimeBase,
- IN UINT16 ImageType,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath
- )
- {
- EFI_STATUS Status;
- TCG_PCR_EVENT *TcgEvent;
- EFI_IMAGE_LOAD_EVENT *ImageLoad;
- UINT32 FilePathSize;
- VOID *Sha1Ctx;
- UINTN CtxSize;
- EFI_IMAGE_DOS_HEADER *DosHdr;
- UINT32 PeCoffHeaderOffset;
- EFI_IMAGE_SECTION_HEADER *Section;
- UINT8 *HashBase;
- UINTN HashSize;
- UINTN SumOfBytesHashed;
- EFI_IMAGE_SECTION_HEADER *SectionHeader;
- UINTN Index;
- UINTN Pos;
- UINT32 EventSize;
- UINT32 EventNumber;
- EFI_PHYSICAL_ADDRESS EventLogLastEntry;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
- UINT32 NumberOfRvaAndSizes;
- BOOLEAN HashStatus;
- UINT32 CertSize;
- Status = EFI_UNSUPPORTED;
- ImageLoad = NULL;
- SectionHeader = NULL;
- Sha1Ctx = NULL;
- FilePathSize = (UINT32) GetDevicePathSize (FilePath);
- //
- // Determine destination PCR by BootPolicy
- //
- EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
- TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));
- if (TcgEvent == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- TcgEvent->EventSize = EventSize;
- ImageLoad = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event;
- switch (ImageType) {
- case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
- TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;
- TcgEvent->PCRIndex = 4;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
- TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;
- TcgEvent->PCRIndex = 2;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
- TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;
- TcgEvent->PCRIndex = 2;
- break;
- default:
- DEBUG ((
- EFI_D_ERROR,
- "TcgMeasurePeImage: Unknown subsystem type %d",
- ImageType
- ));
- goto Finish;
- }
- ImageLoad->ImageLocationInMemory = ImageAddress;
- ImageLoad->ImageLengthInMemory = ImageSize;
- ImageLoad->ImageLinkTimeAddress = LinkTimeBase;
- ImageLoad->LengthOfDevicePath = FilePathSize;
- if ((FilePath != NULL) && (FilePathSize != 0)) {
- CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);
- }
- //
- // Check PE/COFF image
- //
- DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
- PeCoffHeaderOffset = 0;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- PeCoffHeaderOffset = DosHdr->e_lfanew;
- }
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
- if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
- goto Finish;
- }
- //
- // PE/COFF Image Measurement
- //
- // NOTE: The following codes/steps are based upon the authenticode image hashing in
- // PE/COFF Specification 8.0 Appendix A.
- //
- //
- // 1. Load the image header into memory.
- // 2. Initialize a SHA hash context.
- CtxSize = Sha1GetContextSize ();
- Sha1Ctx = AllocatePool (CtxSize);
- if (Sha1Ctx == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Finish;
- }
- HashStatus = Sha1Init (Sha1Ctx);
- if (!HashStatus) {
- goto Finish;
- }
- //
- // Measuring PE/COFF Image Header;
- // But CheckSum field and SECURITY data directory (certificate) are excluded
- //
- //
- // 3. Calculate the distance from the base of the image header to the image checksum address.
- // 4. Hash the image header from its base to beginning of the image checksum.
- //
- HashBase = (UINT8 *) (UINTN) ImageAddress;
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- //
- // Use PE32 offset
- //
- NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
- HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
- } else {
- //
- // Use PE32+ offset
- //
- NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
- HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
- }
- HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
- if (!HashStatus) {
- goto Finish;
- }
- //
- // 5. Skip over the image checksum (it occupies a single ULONG).
- //
- if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
- //
- // 6. Since there is no Cert Directory in optional header, hash everything
- // from the end of the checksum to the end of image header.
- //
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- //
- // Use PE32 offset.
- //
- HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
- HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
- } else {
- //
- // Use PE32+ offset.
- //
- HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
- HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
- }
- if (HashSize != 0) {
- HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
- if (!HashStatus) {
- goto Finish;
- }
- }
- } else {
- //
- // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
- //
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- //
- // Use PE32 offset
- //
- HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
- HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
- } else {
- //
- // Use PE32+ offset
- //
- HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
- HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
- }
- if (HashSize != 0) {
- HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
- if (!HashStatus) {
- goto Finish;
- }
- }
- //
- // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
- // 9. Hash everything from the end of the Cert Directory to the end of image header.
- //
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- //
- // Use PE32 offset
- //
- HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
- HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
- } else {
- //
- // Use PE32+ offset
- //
- HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
- HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
- }
- if (HashSize != 0) {
- HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
- if (!HashStatus) {
- goto Finish;
- }
- }
- }
- //
- // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
- //
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- //
- // Use PE32 offset
- //
- SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
- } else {
- //
- // Use PE32+ offset
- //
- SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
- }
- //
- // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
- // structures in the image. The 'NumberOfSections' field of the image
- // header indicates how big the table should be. Do not include any
- // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
- //
- SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
- if (SectionHeader == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Finish;
- }
- //
- // 12. Using the 'PointerToRawData' in the referenced section headers as
- // a key, arrange the elements in the table in ascending order. In other
- // words, sort the section headers according to the disk-file offset of
- // the section.
- //
- Section = (EFI_IMAGE_SECTION_HEADER *) (
- (UINT8 *) (UINTN) ImageAddress +
- PeCoffHeaderOffset +
- sizeof(UINT32) +
- sizeof(EFI_IMAGE_FILE_HEADER) +
- Hdr.Pe32->FileHeader.SizeOfOptionalHeader
- );
- for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
- Pos = Index;
- while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
- CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
- Pos--;
- }
- CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
- Section += 1;
- }
- //
- // 13. Walk through the sorted table, bring the corresponding section
- // into memory, and hash the entire section (using the 'SizeOfRawData'
- // field in the section header to determine the amount of data to hash).
- // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
- // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
- //
- for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
- Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
- if (Section->SizeOfRawData == 0) {
- continue;
- }
- HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
- HashSize = (UINTN) Section->SizeOfRawData;
- HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
- if (!HashStatus) {
- goto Finish;
- }
- SumOfBytesHashed += HashSize;
- }
- //
- // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
- // data in the file that needs to be added to the hash. This data begins
- // at file offset SUM_OF_BYTES_HASHED and its length is:
- // FileSize - (CertDirectory->Size)
- //
- if (ImageSize > SumOfBytesHashed) {
- HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
- if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
- CertSize = 0;
- } else {
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- //
- // Use PE32 offset.
- //
- CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
- } else {
- //
- // Use PE32+ offset.
- //
- CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
- }
- }
- if (ImageSize > CertSize + SumOfBytesHashed) {
- HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
- HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
- if (!HashStatus) {
- goto Finish;
- }
- } else if (ImageSize < CertSize + SumOfBytesHashed) {
- goto Finish;
- }
- }
- //
- // 17. Finalize the SHA hash.
- //
- HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest);
- if (!HashStatus) {
- goto Finish;
- }
- //
- // Log the PE data
- //
- EventNumber = 1;
- Status = TcgProtocol->HashLogExtendEvent (
- TcgProtocol,
- (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,
- 0,
- TPM_ALG_SHA,
- TcgEvent,
- &EventNumber,
- &EventLogLastEntry
- );
- if (Status == EFI_OUT_OF_RESOURCES) {
- //
- // Out of resource here means the image is hashed and its result is extended to PCR.
- // But the event log can't be saved since log area is full.
- // Just return EFI_SUCCESS in order not to block the image load.
- //
- Status = EFI_SUCCESS;
- }
- Finish:
- FreePool (TcgEvent);
- if (SectionHeader != NULL) {
- FreePool (SectionHeader);
- }
- if (Sha1Ctx != NULL ) {
- FreePool (Sha1Ctx);
- }
- return Status;
- }
- /**
- The security handler is used to abstract platform-specific policy
- from the DXE core response to an attempt to use a file that returns a
- given status for the authentication check from the section extraction protocol.
- The possible responses in a given SAP implementation may include locking
- flash upon failure to authenticate, attestation logging for all signed drivers,
- and other exception operations. The File parameter allows for possible logging
- within the SAP of the driver.
- If File is NULL, then EFI_INVALID_PARAMETER is returned.
- If the file specified by File with an authentication status specified by
- AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
- If the file specified by File with an authentication status specified by
- AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
- then EFI_ACCESS_DENIED is returned.
- If the file specified by File with an authentication status specified by
- AuthenticationStatus is not safe for the DXE Core to use right now, but it
- might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
- returned.
- @param[in] AuthenticationStatus This is the authentication status returned
- from the securitymeasurement services for the
- input file.
- @param[in] File This is a pointer to the device path of the file that is
- being dispatched. This will optionally be used for logging.
- @param[in] FileBuffer File buffer matches the input file device path.
- @param[in] FileSize Size of File buffer matches the input file device path.
- @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
- @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
- FileBuffer did authenticate, and the platform policy dictates
- that the DXE Foundation may use the file.
- @retval other error value
- **/
- EFI_STATUS
- EFIAPI
- DxeTpmMeasureBootHandler (
- IN UINT32 AuthenticationStatus,
- IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
- IN VOID *FileBuffer,
- IN UINTN FileSize,
- IN BOOLEAN BootPolicy
- )
- {
- EFI_TCG_PROTOCOL *TcgProtocol;
- EFI_STATUS Status;
- TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability;
- UINT32 TCGFeatureFlags;
- EFI_PHYSICAL_ADDRESS EventLogLocation;
- EFI_PHYSICAL_ADDRESS EventLogLastEntry;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;
- EFI_HANDLE Handle;
- EFI_HANDLE TempHandle;
- BOOLEAN ApplicationRequired;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
- EFI_PHYSICAL_ADDRESS FvAddress;
- UINT32 Index;
- Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
- if (EFI_ERROR (Status)) {
- //
- // TCG protocol is not installed. So, TPM is not present.
- // Don't do any measurement, and directly return EFI_SUCCESS.
- //
- return EFI_SUCCESS;
- }
- ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);
- Status = TcgProtocol->StatusCheck (
- TcgProtocol,
- &ProtocolCapability,
- &TCGFeatureFlags,
- &EventLogLocation,
- &EventLogLastEntry
- );
- if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag || (!ProtocolCapability.TPMPresentFlag)) {
- //
- // TPM device doesn't work or activate.
- //
- return EFI_SUCCESS;
- }
- //
- // Copy File Device Path
- //
- OrigDevicePathNode = DuplicateDevicePath (File);
- //
- // 1. Check whether this device path support BlockIo protocol.
- // Is so, this device path may be a GPT device path.
- //
- DevicePathNode = OrigDevicePathNode;
- Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);
- if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {
- //
- // Find the gpt partion on the given devicepath
- //
- DevicePathNode = OrigDevicePathNode;
- ASSERT (DevicePathNode != NULL);
- while (!IsDevicePathEnd (DevicePathNode)) {
- //
- // Find the Gpt partition
- //
- if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&
- DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {
- //
- // Check whether it is a gpt partition or not
- //
- if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER &&
- ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {
- //
- // Change the partition device path to its parent device path (disk) and get the handle.
- //
- DevicePathNode->Type = END_DEVICE_PATH_TYPE;
- DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
- DevicePathNode = OrigDevicePathNode;
- Status = gBS->LocateDevicePath (
- &gEfiDiskIoProtocolGuid,
- &DevicePathNode,
- &Handle
- );
- if (!EFI_ERROR (Status)) {
- //
- // Measure GPT disk.
- //
- Status = TcgMeasureGptTable (TcgProtocol, Handle);
- if (!EFI_ERROR (Status)) {
- //
- // GPT disk check done.
- //
- mMeasureGptTableFlag = TRUE;
- }
- }
- FreePool (OrigDevicePathNode);
- OrigDevicePathNode = DuplicateDevicePath (File);
- ASSERT (OrigDevicePathNode != NULL);
- break;
- }
- }
- DevicePathNode = NextDevicePathNode (DevicePathNode);
- }
- }
- //
- // 2. Measure PE image.
- //
- ApplicationRequired = FALSE;
- //
- // Check whether this device path support FVB protocol.
- //
- DevicePathNode = OrigDevicePathNode;
- Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle);
- if (!EFI_ERROR (Status)) {
- //
- // Don't check FV image, and directly return EFI_SUCCESS.
- // It can be extended to the specific FV authentication according to the different requirement.
- //
- if (IsDevicePathEnd (DevicePathNode)) {
- return EFI_SUCCESS;
- }
- //
- // The PE image from unmeasured Firmware volume need be measured
- // The PE image from measured Firmware volume will be measured according to policy below.
- // If it is driver, do not measure
- // If it is application, still measure.
- //
- ApplicationRequired = TRUE;
- if (mCacheMeasuredHandle != Handle && mMeasuredHobData != NULL) {
- //
- // Search for Root FV of this PE image
- //
- TempHandle = Handle;
- do {
- Status = gBS->HandleProtocol(
- TempHandle,
- &gEfiFirmwareVolumeBlockProtocolGuid,
- (VOID**)&FvbProtocol
- );
- TempHandle = FvbProtocol->ParentHandle;
- } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL);
- //
- // Search in measured FV Hob
- //
- Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress);
- if (EFI_ERROR(Status)){
- return Status;
- }
- ApplicationRequired = FALSE;
- for (Index = 0; Index < mMeasuredHobData->Num; Index++) {
- if(mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {
- //
- // Cache measured FV for next measurement
- //
- mCacheMeasuredHandle = Handle;
- ApplicationRequired = TRUE;
- break;
- }
- }
- }
- }
- //
- // File is not found.
- //
- if (FileBuffer == NULL) {
- Status = EFI_SECURITY_VIOLATION;
- goto Finish;
- }
- mTpmImageSize = FileSize;
- mFileBuffer = FileBuffer;
- //
- // Measure PE Image
- //
- DevicePathNode = OrigDevicePathNode;
- ZeroMem (&ImageContext, sizeof (ImageContext));
- ImageContext.Handle = (VOID *) FileBuffer;
- ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead;
- //
- // Get information about the image being loaded
- //
- Status = PeCoffLoaderGetImageInfo (&ImageContext);
- if (EFI_ERROR (Status)) {
- //
- // The information can't be got from the invalid PeImage
- //
- goto Finish;
- }
- //
- // Measure only application if Application flag is set
- // Measure drivers and applications if Application flag is not set
- //
- if ((!ApplicationRequired) ||
- (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
- //
- // Print the image path to be measured.
- //
- DEBUG_CODE_BEGIN ();
- CHAR16 *ToText;
- ToText = ConvertDevicePathToText (
- DevicePathNode,
- FALSE,
- TRUE
- );
- if (ToText != NULL) {
- DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
- FreePool (ToText);
- }
- DEBUG_CODE_END ();
- //
- // Measure PE image into TPM log.
- //
- Status = TcgMeasurePeImage (
- TcgProtocol,
- (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer,
- FileSize,
- (UINTN) ImageContext.ImageAddress,
- ImageContext.ImageType,
- DevicePathNode
- );
- }
- //
- // Done, free the allocated resource.
- //
- Finish:
- if (OrigDevicePathNode != NULL) {
- FreePool (OrigDevicePathNode);
- }
- return Status;
- }
- /**
- Register the security handler to provide TPM measure boot service.
- @param ImageHandle ImageHandle of the loaded driver.
- @param SystemTable Pointer to the EFI System Table.
- @retval EFI_SUCCESS Register successfully.
- @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
- **/
- EFI_STATUS
- EFIAPI
- DxeTpmMeasureBootLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_HOB_GUID_TYPE *GuidHob;
- GuidHob = NULL;
- GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);
- if (GuidHob != NULL) {
- mMeasuredHobData = GET_GUID_HOB_DATA (GuidHob);
- }
- return RegisterSecurity2Handler (
- DxeTpmMeasureBootHandler,
- EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
- );
- }
|