Updates the sanitation function names to be lib unique names Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> Message-Id: <355aa846a99ca6ac0f7574cf5982661da0d9fea6.1705529990.git.doug.edk2@gmail.com> Reviewed-by: Jiewen Yao <Jiewen.yao@intel.com>
		
			
				
	
	
		
			286 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			286 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The library instance provides security service of TPM measure boot and
 | 
						|
  Confidential Computing (CC) 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.
 | 
						|
 | 
						|
  This file will pull out the validation logic from the following functions, in an
 | 
						|
  attempt to validate the untrusted input in the form of unit tests
 | 
						|
 | 
						|
  These are those functions:
 | 
						|
 | 
						|
  DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
 | 
						|
  read is within the image buffer.
 | 
						|
 | 
						|
  Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
 | 
						|
  partition data carefully.
 | 
						|
 | 
						|
  Copyright (c) Microsoft Corporation.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
**/
 | 
						|
#include <Uefi.h>
 | 
						|
#include <Uefi/UefiSpec.h>
 | 
						|
#include <Library/SafeIntLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <IndustryStandard/UefiTcgPlatform.h>
 | 
						|
#include <Protocol/BlockIo.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
 | 
						|
#include "DxeTpmMeasureBootLibSanitization.h"
 | 
						|
 | 
						|
#define GPT_HEADER_REVISION_V1  0x00010000
 | 
						|
 | 
						|
/**
 | 
						|
  This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
 | 
						|
  However this function will not attempt to verify the validity of the GPT partition
 | 
						|
  It will check the following:
 | 
						|
    - Signature
 | 
						|
    - Revision
 | 
						|
    - AlternateLBA
 | 
						|
    - FirstUsableLBA
 | 
						|
    - LastUsableLBA
 | 
						|
    - PartitionEntryLBA
 | 
						|
    - NumberOfPartitionEntries
 | 
						|
    - SizeOfPartitionEntry
 | 
						|
    - BlockIo
 | 
						|
 | 
						|
  @param[in] PrimaryHeader
 | 
						|
    Pointer to the EFI_PARTITION_TABLE_HEADER structure.
 | 
						|
 | 
						|
  @param[in] BlockIo
 | 
						|
    Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
    The EFI_PARTITION_TABLE_HEADER structure is valid.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER
 | 
						|
    The EFI_PARTITION_TABLE_HEADER structure is invalid.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TpmSanitizeEfiPartitionTableHeader (
 | 
						|
  IN CONST EFI_PARTITION_TABLE_HEADER  *PrimaryHeader,
 | 
						|
  IN CONST EFI_BLOCK_IO_PROTOCOL       *BlockIo
 | 
						|
  )
 | 
						|
{
 | 
						|
  // Verify that the input parameters are safe to use
 | 
						|
  if (PrimaryHeader == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
 | 
						|
  if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
 | 
						|
  if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
 | 
						|
  if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  // check that the PartitionEntryLBA greater than the Max LBA
 | 
						|
  // This will be used later for multiplication
 | 
						|
  if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  // Check that the number of partition entries is greater than zero
 | 
						|
  if (PrimaryHeader->NumberOfPartitionEntries == 0) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
 | 
						|
  if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  // This check is to prevent overflow when calculating the allocation size for the partition entries
 | 
						|
  // This check will be used later for multiplication
 | 
						|
  if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function will validate that the allocation size from the primary header is sane
 | 
						|
  It will check the following:
 | 
						|
    - AllocationSize does not overflow
 | 
						|
 | 
						|
  @param[in] PrimaryHeader
 | 
						|
    Pointer to the EFI_PARTITION_TABLE_HEADER structure.
 | 
						|
 | 
						|
  @param[out] AllocationSize
 | 
						|
    Pointer to the allocation size.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
    The allocation size is valid.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES
 | 
						|
    The allocation size is invalid.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TpmSanitizePrimaryHeaderAllocationSize (
 | 
						|
  IN CONST EFI_PARTITION_TABLE_HEADER  *PrimaryHeader,
 | 
						|
  OUT UINT32                           *AllocationSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if (PrimaryHeader == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (AllocationSize == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // Replacing logic:
 | 
						|
  // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
 | 
						|
  Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function will validate that the Gpt Event Size calculated from the primary header is sane
 | 
						|
  It will check the following:
 | 
						|
    - EventSize does not overflow
 | 
						|
 | 
						|
  Important: This function includes the entire length of the allocated space, including the
 | 
						|
  TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
 | 
						|
  the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
 | 
						|
 | 
						|
  @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
 | 
						|
  @param[in] NumberOfPartition - Number of partitions.
 | 
						|
  @param[out] EventSize - Pointer to the event size.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
    The event size is valid.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES
 | 
						|
    Overflow would have occurred.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER
 | 
						|
    One of the passed parameters was invalid.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TpmSanitizePrimaryHeaderGptEventSize (
 | 
						|
  IN  CONST EFI_PARTITION_TABLE_HEADER  *PrimaryHeader,
 | 
						|
  IN  UINTN                             NumberOfPartition,
 | 
						|
  OUT UINT32                            *EventSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      SafeNumberOfPartitions;
 | 
						|
 | 
						|
  if (PrimaryHeader == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EventSize == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
 | 
						|
  Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // Replacing logic:
 | 
						|
  // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR));
 | 
						|
  Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = SafeUint32Add (
 | 
						|
             sizeof (TCG_PCR_EVENT_HDR) +
 | 
						|
             OFFSET_OF (EFI_GPT_DATA, Partitions),
 | 
						|
             *EventSize,
 | 
						|
             EventSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function will validate that the PeImage Event Size from the loaded image is sane
 | 
						|
  It will check the following:
 | 
						|
    - EventSize does not overflow
 | 
						|
 | 
						|
  @param[in] FilePathSize - Size of the file path.
 | 
						|
  @param[out] EventSize - Pointer to the event size.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
    The event size is valid.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES
 | 
						|
    Overflow would have occurred.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER
 | 
						|
    One of the passed parameters was invalid.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TpmSanitizePeImageEventSize (
 | 
						|
  IN  UINT32  FilePathSize,
 | 
						|
  OUT UINT32  *EventSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  // Replacing logic:
 | 
						|
  // sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
 | 
						|
  Status = SafeUint32Add (OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath), FilePathSize, EventSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n"));
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  // Replacing logic:
 | 
						|
  // EventSize + sizeof (TCG_PCR_EVENT_HDR)
 | 
						|
  Status = SafeUint32Add (*EventSize, sizeof (TCG_PCR_EVENT_HDR), EventSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n"));
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |