X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=SecurityPkg%2FLibrary%2FDxeTpmMeasureBootLib%2FDxeTpmMeasureBootLib.c;h=d990eb2ad3a9f8007cb49bb50075e2cfc9bcddc3;hp=300a15fe6b6f9db17381879a559ee73c31c912f9;hb=HEAD;hpb=4dbb98ab164c70d788b956723199c90018467648 diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c index 300a15fe6b..220393dd2b 100644 --- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c @@ -1,5 +1,5 @@ /** @file - The library instance provides security service of TPM measure boot. + 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. @@ -15,24 +15,19 @@ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse partition data carefully. -Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include -#include #include #include -#include +#include + +#include #include #include @@ -43,15 +38,20 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include // // Flag to check GPT partition. It only need be measured once. // -BOOLEAN mMeasureGptTableFlag = FALSE; -EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; -UINTN mMeasureGptCount = 0; -VOID *mFileBuffer; -UINTN mImageSize; +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. @@ -62,24 +62,24 @@ UINTN mImageSize; @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. + @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 + + @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 + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer ) { - UINTN EndPosition; + UINTN EndPosition; - if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) { + if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { return EFI_INVALID_PARAMETER; } @@ -88,15 +88,15 @@ DxeTpmMeasureBootLibImageRead ( } EndPosition = FileOffset + *ReadSize; - if (EndPosition > mImageSize) { - *ReadSize = (UINT32)(mImageSize - FileOffset); + if (EndPosition > mTpmImageSize) { + *ReadSize = (UINT32)(mTpmImageSize - FileOffset); } - if (FileOffset >= mImageSize) { + if (FileOffset >= mTpmImageSize) { *ReadSize = 0; } - CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); return EFI_SUCCESS; } @@ -119,43 +119,46 @@ DxeTpmMeasureBootLibImageRead ( EFI_STATUS EFIAPI TcgMeasureGptTable ( - IN EFI_TCG_PROTOCOL *TcgProtocol, - IN EFI_HANDLE GptHandle + 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; + 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); + Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo); if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } - Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo); + + 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); + // + PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *)AllocatePool (BlockIo->Media->BlockSize); if (PrimaryHeader == NULL) { return EFI_OUT_OF_RESOURCES; - } + } + Status = DiskIo->ReadDisk ( DiskIo, BlockIo->Media->MediaId, @@ -164,10 +167,11 @@ TcgMeasureGptTable ( (UINT8 *)PrimaryHeader ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n")); + DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); FreePool (PrimaryHeader); return EFI_DEVICE_ERROR; - } + } + // // Read the partition entry. // @@ -176,10 +180,11 @@ TcgMeasureGptTable ( FreePool (PrimaryHeader); return EFI_OUT_OF_RESOURCES; } + Status = DiskIo->ReadDisk ( DiskIo, BlockIo->Media->MediaId, - MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, EntryPtr ); @@ -188,48 +193,49 @@ TcgMeasureGptTable ( 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 (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) { - NumberOfPartition++; + 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)); + // + 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; + 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)); + // + CopyMem ((UINT8 *)GptData, (UINT8 *)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER)); GptData->NumberOfPartitions = NumberOfPartition; // // Copy the valid partition entry // - PartitionEntry = (EFI_PARTITION_ENTRY*)EntryPtr; + PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr; NumberOfPartition = 0; for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { - if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) { + if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) { CopyMem ( (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry, (UINT8 *)PartitionEntry, @@ -237,22 +243,23 @@ TcgMeasureGptTable ( ); NumberOfPartition++; } - PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry); + + 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 - ); + Status = TcgProtocol->HashLogExtendEvent ( + TcgProtocol, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, + (UINT64)TcgEvent->EventSize, + TPM_ALG_SHA, + TcgEvent, + &EventNumber, + &EventLogLastEntry + ); if (!EFI_ERROR (Status)) { mMeasureGptCount++; } @@ -272,6 +279,9 @@ TcgMeasureGptTable ( 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 @@ -281,7 +291,7 @@ TcgMeasureGptTable ( @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 EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. @retval other error value **/ @@ -311,7 +321,6 @@ TcgMeasurePeImage ( EFI_IMAGE_SECTION_HEADER *SectionHeader; UINTN Index; UINTN Pos; - UINT16 Magic; UINT32 EventSize; UINT32 EventNumber; EFI_PHYSICAL_ADDRESS EventLogLastEntry; @@ -324,19 +333,19 @@ TcgMeasurePeImage ( ImageLoad = NULL; SectionHeader = NULL; Sha1Ctx = NULL; - FilePathSize = (UINT32) GetDevicePathSize (FilePath); + FilePathSize = (UINT32)GetDevicePathSize (FilePath); // // Determine destination PCR by BootPolicy // EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; - TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT)); + 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; + ImageLoad = (EFI_IMAGE_LOAD_EVENT *)TcgEvent->Event; switch (ImageType) { case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: @@ -353,7 +362,7 @@ TcgMeasurePeImage ( break; default: DEBUG (( - EFI_D_ERROR, + DEBUG_ERROR, "TcgMeasurePeImage: Unknown subsystem type %d", ImageType )); @@ -364,18 +373,20 @@ TcgMeasurePeImage ( ImageLoad->ImageLengthInMemory = ImageSize; ImageLoad->ImageLinkTimeAddress = LinkTimeBase; ImageLoad->LengthOfDevicePath = FilePathSize; - CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize); + if ((FilePath != NULL) && (FilePathSize != 0)) { + CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize); + } // // Check PE/COFF image // - DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress; + 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); + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset); if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { goto Finish; } @@ -407,44 +418,30 @@ TcgMeasurePeImage ( // Measuring PE/COFF Image Header; // But CheckSum field and SECURITY data directory (certificate) are excluded // - if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value - // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the - // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - // - Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; - } else { - // - // Get the magic value from the PE/COFF Optional Header - // - Magic = Hdr.Pe32->OptionalHeader.Magic; - } - + // // 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 (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + 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) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase); + HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; } else { // // Use PE32+ offset // NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; - HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase); + 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). @@ -454,46 +451,46 @@ TcgMeasurePeImage ( // 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 (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + 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); + 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); + HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); } if (HashSize != 0) { - HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); + 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 (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset // - HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + 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) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + // + 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); + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); if (!HashStatus) { goto Finish; } @@ -503,22 +500,22 @@ TcgMeasurePeImage ( // 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 (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + 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); + 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); + 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); + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); if (!HashStatus) { goto Finish; } @@ -528,7 +525,7 @@ TcgMeasurePeImage ( // // 10. Set the SUM_OF_BYTES_HASHED to the size of the header // - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset // @@ -546,7 +543,7 @@ TcgMeasurePeImage ( // 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); + 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; @@ -558,20 +555,21 @@ TcgMeasurePeImage ( // 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 - ); + 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)); + CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); Pos--; } - CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER)); + + CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); Section += 1; } @@ -583,12 +581,13 @@ TcgMeasurePeImage ( // 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]; + Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; if (Section->SizeOfRawData == 0) { continue; } - HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData; - HashSize = (UINTN) Section->SizeOfRawData; + + HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData; + HashSize = (UINTN)Section->SizeOfRawData; HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); if (!HashStatus) { @@ -605,12 +604,12 @@ TcgMeasurePeImage ( // FileSize - (CertDirectory->Size) // if (ImageSize > SumOfBytesHashed) { - HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed; + HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed; if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { CertSize = 0; } else { - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset. // @@ -624,7 +623,7 @@ TcgMeasurePeImage ( } if (ImageSize > CertSize + SumOfBytesHashed) { - HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed); + HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed); HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); if (!HashStatus) { @@ -638,7 +637,7 @@ TcgMeasurePeImage ( // // 17. Finalize the SHA hash. // - HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest); + HashStatus = Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest); if (!HashStatus) { goto Finish; } @@ -647,15 +646,23 @@ TcgMeasurePeImage ( // Log the PE data // EventNumber = 1; - Status = TcgProtocol->HashLogExtendEvent ( - TcgProtocol, - (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL, - 0, - TPM_ALG_SHA, - TcgEvent, - &EventNumber, - &EventLogLastEntry - ); + 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); @@ -667,33 +674,34 @@ Finish: 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 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 + 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 + 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, + 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 + 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. + If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED. + @param[in] AuthenticationStatus This is the authentication status returned from the securitymeasurement services for the input file. @@ -711,26 +719,30 @@ Finish: EFI_STATUS EFIAPI DxeTpmMeasureBootHandler ( - IN UINT32 AuthenticationStatus, - IN CONST EFI_DEVICE_PATH_PROTOCOL *File, - IN VOID *FileBuffer, - IN UINTN FileSize, - IN BOOLEAN BootPolicy + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File OPTIONAL, + 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; - BOOLEAN ApplicationRequired; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - - Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol); + 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. @@ -739,15 +751,15 @@ DxeTpmMeasureBootHandler ( return EFI_SUCCESS; } - ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability); - Status = TcgProtocol->StatusCheck ( - TcgProtocol, - &ProtocolCapability, - &TCGFeatureFlags, - &EventLogLocation, - &EventLogLastEntry - ); - if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) { + 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. // @@ -758,16 +770,16 @@ DxeTpmMeasureBootHandler ( // 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); + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle); if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) { // - // Find the gpt partion on the given devicepath + // Find the gpt partition on the given devicepath // DevicePathNode = OrigDevicePathNode; ASSERT (DevicePathNode != NULL); @@ -775,25 +787,26 @@ DxeTpmMeasureBootHandler ( // // Find the Gpt partition // - if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH && - DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) { + 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) { - + // + 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 - ); + Status = gBS->LocateDevicePath ( + &gEfiDiskIoProtocolGuid, + &DevicePathNode, + &Handle + ); if (!EFI_ERROR (Status)) { // // Measure GPT disk. @@ -806,26 +819,28 @@ DxeTpmMeasureBootHandler ( mMeasureGptTableFlag = TRUE; } } + FreePool (OrigDevicePathNode); OrigDevicePathNode = DuplicateDevicePath (File); ASSERT (OrigDevicePathNode != NULL); break; } } - DevicePathNode = NextDevicePathNode (DevicePathNode); + + DevicePathNode = NextDevicePathNode (DevicePathNode); } } - + // // 2. Measure PE image. // ApplicationRequired = FALSE; // - // Check whether this device path support FV2 protocol. + // Check whether this device path support FVB protocol. // DevicePathNode = OrigDevicePathNode; - Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle); + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle); if (!EFI_ERROR (Status)) { // // Don't check FV image, and directly return EFI_SUCCESS. @@ -834,14 +849,52 @@ DxeTpmMeasureBootHandler ( if (IsDevicePathEnd (DevicePathNode)) { return EFI_SUCCESS; } + // - // The image from Firmware image will not be mearsured. - // Current policy doesn't measure PeImage from Firmware if it is driver - // If the got PeImage is application, it will be still be measured. + // 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. // @@ -850,55 +903,57 @@ DxeTpmMeasureBootHandler ( goto Finish; } - mImageSize = FileSize; - mFileBuffer = FileBuffer; + 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; + 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)) { + // + // Check for invalid parameters. + // + if (File == NULL) { + return EFI_ACCESS_DENIED; + } + // // 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)) { + if ((!ApplicationRequired) || + (ApplicationRequired && (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION))) + { // // Print the image path to be measured. - // + // DEBUG_CODE_BEGIN (); - CHAR16 *ToText; - EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; - Status = gBS->LocateProtocol ( - &gEfiDevicePathToTextProtocolGuid, - NULL, - (VOID **) &DevPathToText - ); - if (!EFI_ERROR (Status)) { - ToText = DevPathToText->ConvertDevicePathToText ( - DevicePathNode, - FALSE, - TRUE - ); - if (ToText != NULL) { - DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText)); - } - } + 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 (); // @@ -906,10 +961,10 @@ DxeTpmMeasureBootHandler ( // Status = TcgMeasurePeImage ( TcgProtocol, - (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, - FileSize, - (UINTN) ImageContext.ImageAddress, - ImageContext.ImageType, + (EFI_PHYSICAL_ADDRESS)(UINTN)FileBuffer, + FileSize, + (UINTN)ImageContext.ImageAddress, + ImageContext.ImageType, DevicePathNode ); } @@ -941,8 +996,18 @@ DxeTpmMeasureBootLibConstructor ( 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 - ); + DxeTpmMeasureBootHandler, + EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED + ); }