https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			340 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Measure TCG required variable.
 | 
						|
 | 
						|
Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <PiDxe.h>
 | 
						|
#include <Guid/ImageAuthentication.h>
 | 
						|
#include <IndustryStandard/UefiTcgPlatform.h>
 | 
						|
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/UefiRuntimeServicesTableLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/TpmMeasurementLib.h>
 | 
						|
 | 
						|
#include "PrivilegePolymorphic.h"
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  CHAR16                                 *VariableName;
 | 
						|
  EFI_GUID                               *VendorGuid;
 | 
						|
} VARIABLE_TYPE;
 | 
						|
 | 
						|
VARIABLE_TYPE  mVariableType[] = {
 | 
						|
  {EFI_SECURE_BOOT_MODE_NAME,    &gEfiGlobalVariableGuid},
 | 
						|
  {EFI_PLATFORM_KEY_NAME,        &gEfiGlobalVariableGuid},
 | 
						|
  {EFI_KEY_EXCHANGE_KEY_NAME,    &gEfiGlobalVariableGuid},
 | 
						|
  {EFI_IMAGE_SECURITY_DATABASE,  &gEfiImageSecurityDatabaseGuid},
 | 
						|
  {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid},
 | 
						|
  {EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid},
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// "SecureBoot" may update following PK Del/Add
 | 
						|
//  Cache its value to detect value update
 | 
						|
//
 | 
						|
UINT8       *mSecureBootVarData    = NULL;
 | 
						|
UINTN       mSecureBootVarDataSize = 0;
 | 
						|
 | 
						|
/**
 | 
						|
  This function will return if this variable is SecureBootPolicy Variable.
 | 
						|
 | 
						|
  @param[in]  VariableName      A Null-terminated string that is the name of the vendor's variable.
 | 
						|
  @param[in]  VendorGuid        A unique identifier for the vendor.
 | 
						|
 | 
						|
  @retval TRUE  This is SecureBootPolicy Variable
 | 
						|
  @retval FALSE This is not SecureBootPolicy Variable
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsSecureBootPolicyVariable (
 | 
						|
  IN CHAR16                                 *VariableName,
 | 
						|
  IN EFI_GUID                               *VendorGuid
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
 | 
						|
    if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
 | 
						|
        (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Measure and log an EFI variable, and extend the measurement result into a specific PCR.
 | 
						|
 | 
						|
  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.
 | 
						|
  @param[in]  VendorGuid        A unique identifier for the vendor.
 | 
						|
  @param[in]  VarData           The content of the variable data.
 | 
						|
  @param[in]  VarSize           The size of the variable data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Operation completed successfully.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Out of memory.
 | 
						|
  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
MeasureVariable (
 | 
						|
  IN      CHAR16                    *VarName,
 | 
						|
  IN      EFI_GUID                  *VendorGuid,
 | 
						|
  IN      VOID                      *VarData,
 | 
						|
  IN      UINTN                     VarSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  UINTN                             VarNameLength;
 | 
						|
  UEFI_VARIABLE_DATA                *VarLog;
 | 
						|
  UINT32                            VarLogSize;
 | 
						|
 | 
						|
  ASSERT ((VarSize == 0 && VarData == NULL) || (VarSize != 0 && VarData != NULL));
 | 
						|
 | 
						|
  VarNameLength      = StrLen (VarName);
 | 
						|
  VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
 | 
						|
                        - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
 | 
						|
 | 
						|
  VarLog = (UEFI_VARIABLE_DATA *) AllocateZeroPool (VarLogSize);
 | 
						|
  if (VarLog == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName));
 | 
						|
  VarLog->UnicodeNameLength  = VarNameLength;
 | 
						|
  VarLog->VariableDataLength = VarSize;
 | 
						|
  CopyMem (
 | 
						|
     VarLog->UnicodeName,
 | 
						|
     VarName,
 | 
						|
     VarNameLength * sizeof (*VarName)
 | 
						|
     );
 | 
						|
  if (VarSize != 0) {
 | 
						|
    CopyMem (
 | 
						|
       (CHAR16 *)VarLog->UnicodeName + VarNameLength,
 | 
						|
       VarData,
 | 
						|
       VarSize
 | 
						|
       );
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "VariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_DRIVER_CONFIG));
 | 
						|
  DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
 | 
						|
 | 
						|
  Status = TpmMeasureAndLogData (
 | 
						|
             7,
 | 
						|
             EV_EFI_VARIABLE_DRIVER_CONFIG,
 | 
						|
             VarLog,
 | 
						|
             VarLogSize,
 | 
						|
             VarLog,
 | 
						|
             VarLogSize
 | 
						|
             );
 | 
						|
  FreePool (VarLog);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the status whether get the variable success. The function retrieves
 | 
						|
  variable  through the UEFI Runtime Service GetVariable().  The
 | 
						|
  returned buffer is allocated using AllocatePool().  The caller is responsible
 | 
						|
  for freeing this buffer with FreePool().
 | 
						|
 | 
						|
  This API is only invoked in boot time. It may NOT be invoked at runtime.
 | 
						|
 | 
						|
  @param[in]  Name  The pointer to a Null-terminated Unicode string.
 | 
						|
  @param[in]  Guid  The pointer to an EFI_GUID structure
 | 
						|
  @param[out] Value The buffer point saved the variable info.
 | 
						|
  @param[out] Size  The buffer size of the variable.
 | 
						|
 | 
						|
  @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
 | 
						|
  @return EFI_SUCCESS               Find the specified variable.
 | 
						|
  @return Others Errors             Return errors from call to gRT->GetVariable.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InternalGetVariable (
 | 
						|
  IN CONST CHAR16    *Name,
 | 
						|
  IN CONST EFI_GUID  *Guid,
 | 
						|
  OUT VOID           **Value,
 | 
						|
  OUT UINTN          *Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINTN       BufferSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to get the variable size.
 | 
						|
  //
 | 
						|
  BufferSize = 0;
 | 
						|
  *Value     = NULL;
 | 
						|
  if (Size != NULL) {
 | 
						|
    *Size  = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
 | 
						|
  if (Status != EFI_BUFFER_TOO_SMALL) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate buffer to get the variable.
 | 
						|
  //
 | 
						|
  *Value = AllocatePool (BufferSize);
 | 
						|
  ASSERT (*Value != NULL);
 | 
						|
  if (*Value == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the variable data.
 | 
						|
  //
 | 
						|
  Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool(*Value);
 | 
						|
    *Value = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Size != NULL) {
 | 
						|
    *Size = BufferSize;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  SecureBoot Hook for SetVariable.
 | 
						|
 | 
						|
  @param[in] VariableName                 Name of Variable to be found.
 | 
						|
  @param[in] VendorGuid                   Variable vendor GUID.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
SecureBootHook (
 | 
						|
  IN CHAR16                                 *VariableName,
 | 
						|
  IN EFI_GUID                               *VendorGuid
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  UINTN                             VariableDataSize;
 | 
						|
  VOID                              *VariableData;
 | 
						|
 | 
						|
  if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // We should NOT use Data and DataSize here,because it may include signature,
 | 
						|
  // or is just partial with append attributes, or is deleted.
 | 
						|
  // We should GetVariable again, to get full variable content.
 | 
						|
  //
 | 
						|
  Status = InternalGetVariable (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             &VariableData,
 | 
						|
             &VariableDataSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Measure DBT only if present and not empty
 | 
						|
    //
 | 
						|
    if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0 &&
 | 
						|
        CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) {
 | 
						|
      DEBUG((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2));
 | 
						|
      return;
 | 
						|
    } else {
 | 
						|
      VariableData     = NULL;
 | 
						|
      VariableDataSize = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = MeasureVariable (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             VariableData,
 | 
						|
             VariableDataSize
 | 
						|
             );
 | 
						|
  DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
 | 
						|
 | 
						|
  if (VariableData != NULL) {
 | 
						|
    FreePool (VariableData);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // "SecureBoot" is 8bit & read-only. It can only be changed according to PK update
 | 
						|
  //
 | 
						|
  if ((StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0) &&
 | 
						|
       CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
 | 
						|
     Status = InternalGetVariable (
 | 
						|
                EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
                &gEfiGlobalVariableGuid,
 | 
						|
                &VariableData,
 | 
						|
                &VariableDataSize
 | 
						|
                );
 | 
						|
     if (EFI_ERROR (Status)) {
 | 
						|
       return;
 | 
						|
     }
 | 
						|
 | 
						|
     //
 | 
						|
     // If PK update is successful. "SecureBoot" shall always exist ever since variable write service is ready
 | 
						|
     //
 | 
						|
     ASSERT(mSecureBootVarData != NULL);
 | 
						|
 | 
						|
     if (CompareMem(mSecureBootVarData, VariableData, VariableDataSize) != 0) {
 | 
						|
       FreePool(mSecureBootVarData);
 | 
						|
       mSecureBootVarData     = VariableData;
 | 
						|
       mSecureBootVarDataSize = VariableDataSize;
 | 
						|
 | 
						|
       DEBUG((DEBUG_INFO, "%s variable updated according to PK change. Remeasure the value!\n", EFI_SECURE_BOOT_MODE_NAME));
 | 
						|
       Status = MeasureVariable (
 | 
						|
                  EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  mSecureBootVarData,
 | 
						|
                  mSecureBootVarDataSize
 | 
						|
                  );
 | 
						|
       DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status));
 | 
						|
     } else {
 | 
						|
       //
 | 
						|
       // "SecureBoot" variable is not changed
 | 
						|
       //
 | 
						|
       FreePool(VariableData);
 | 
						|
     }
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
 | 
						|
  Record their initial State when variable write service is ready.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
RecordSecureBootPolicyVarData(
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Record initial "SecureBoot" variable value.
 | 
						|
  // It is used to detect SecureBoot variable change in SecureBootHook.
 | 
						|
  //
 | 
						|
  Status = InternalGetVariable (
 | 
						|
             EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             (VOID **)&mSecureBootVarData,
 | 
						|
             &mSecureBootVarDataSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    //
 | 
						|
    // Read could fail when Auth Variable solution is not supported
 | 
						|
    //
 | 
						|
    DEBUG((DEBUG_INFO, "RecordSecureBootPolicyVarData GetVariable %s Status %x\n", EFI_SECURE_BOOT_MODE_NAME, Status));
 | 
						|
  }
 | 
						|
}
 |