12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013 |
- /** @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 ((DEBUG_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 ((
- DEBUG_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 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.
- 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.
- @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 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;
- 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 partition 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)) {
- //
- // 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)))
- {
- //
- // 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
- );
- }
|