alder_lake_bios/Intel/AlderLake/AlderLakePlatSamplePkg/Platform/BiosInfoChecker/BiosInfoChecker.c

359 lines
12 KiB
C

/** @file
@copyright
INTEL CONFIDENTIAL
Copyright 2017 - 2020 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains 'Framework Code' and is licensed as such under the terms
of your license agreement with Intel or your vendor. This file may not be
modified, except as allowed by additional terms of your license agreement.
@par Specification Reference:
**/
#include <PiPei.h>
#include <Guid/BiosInfo.h>
#include <Guid/FirmwareContentsSigned.h>
#include <Library/PeiServicesLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
#define FIT_TABLE_TYPE_BIOS_MODULE 7
/**
Check if a block of buffer is erased.
@param[in] ErasePolarity Erase polarity attribute of the firmware volume
@param[in] InBuffer The buffer to be checked
@param[in] BufferSize Size of the buffer in bytes
@retval TRUE The block of buffer is erased
@retval FALSE The block of buffer is not erased
**/
BOOLEAN
IsBufferErased (
IN UINT8 ErasePolarity,
IN VOID *InBuffer,
IN UINTN BufferSize
)
{
UINTN Count;
UINT8 EraseByte;
UINT8 *Buffer;
if(ErasePolarity == 1) {
EraseByte = 0xFF;
} else {
EraseByte = 0;
}
Buffer = InBuffer;
for (Count = 0; Count < BufferSize; Count++) {
if (Buffer[Count] != EraseByte) {
return FALSE;
}
}
return TRUE;
}
/**
Return if this FFS has single signed section.
@param[in] FileBuffer
@param[in] FileBufferSize
@retval TRUE Single signed section found.
@retval FALSE Unsigned section found
**/
BOOLEAN
HasSingleSignedSection (
IN VOID *FileBuffer,
IN UINT32 FileBufferSize
)
{
EFI_COMMON_SECTION_HEADER *SectionHeader;
UINTN SectionSize;
BOOLEAN FindSignSection;
DEBUG ((DEBUG_INFO, "HasSingleSignedSection - FFS: 0x%08x - 0x%08x\n", FileBuffer, FileBufferSize));
//
// Find Section
//
if (IS_FFS_FILE2(FileBuffer)) {
SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINTN)FileBuffer + sizeof(EFI_FFS_FILE_HEADER2));
DEBUG ((DEBUG_INFO, " Guid = 0x%g\n", &((EFI_GUID_DEFINED_SECTION2 *)SectionHeader)->SectionDefinitionGuid));
DEBUG ((DEBUG_INFO, " DataOfset = 0x%X\n", ((EFI_GUID_DEFINED_SECTION2 *)SectionHeader)->DataOffset));
} else {
SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINTN)FileBuffer + sizeof(EFI_FFS_FILE_HEADER));
DEBUG ((DEBUG_INFO, " Guid = 0x%g\n", &((EFI_GUID_DEFINED_SECTION *)SectionHeader)->SectionDefinitionGuid));
DEBUG ((DEBUG_INFO, " DataOfset = 0x%X\n", ((EFI_GUID_DEFINED_SECTION *)SectionHeader)->DataOffset));
}
SectionHeader = (EFI_COMMON_SECTION_HEADER *)ALIGN_POINTER(SectionHeader, 4);
FindSignSection = FALSE;
while ((UINTN)SectionHeader < (UINTN)FileBuffer + FileBufferSize) {
DEBUG ((DEBUG_INFO, "HasSingleSignedSection - Section: 0x%08x\n", SectionHeader));
if (IS_SECTION2(SectionHeader)) {
SectionSize = SECTION2_SIZE(SectionHeader);
} else {
SectionSize = SECTION_SIZE(SectionHeader);
}
SectionSize = GET_OCCUPIED_SIZE (SectionSize, 4);
DEBUG ((DEBUG_INFO, " Size = 0x%X\n", SectionSize));
DEBUG ((DEBUG_INFO, " Type = 0x%X\n", SectionHeader->Type));
if ((SectionHeader->Type == EFI_SECTION_GUID_DEFINED) &&
((((EFI_GUID_DEFINED_SECTION *)SectionHeader)->Attributes & (EFI_GUIDED_SECTION_AUTH_STATUS_VALID | EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) != 0) &&
(CompareGuid (&((EFI_GUID_DEFINED_SECTION *)SectionHeader)->SectionDefinitionGuid, &gEfiCertTypeRsa2048Sha256Guid))) {
//
// record it
//
FindSignSection = TRUE;
} else if (SectionHeader->Type == EFI_SECTION_PEI_DEPEX ||
SectionHeader->Type == EFI_SECTION_DXE_DEPEX ||
SectionHeader->Type == EFI_SECTION_SMM_DEPEX ||
SectionHeader->Type == EFI_SECTION_USER_INTERFACE) {
//
// If it's DEPEX or UI section then do nothing and go next section
//
} else {
//
// Any unsigned section is not allowed
//
if (SectionHeader->Type != EFI_SECTION_GUID_DEFINED) {
DEBUG ((DEBUG_ERROR, "HasSingleSignedSection - invalid section type %x\n", SectionHeader->Type));
} else {
DEBUG ((DEBUG_ERROR, "HasSingleSignedSection - invalid section GUID %g\n", &((EFI_GUID_DEFINED_SECTION *)SectionHeader)->SectionDefinitionGuid));
}
return FALSE;
}
//
// Next Section
//
SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINTN)SectionHeader + SectionSize);
}
return FindSignSection;
}
/**
Return if this FV has single signed FFS.
@param[in] FvStart
@param[in] FvSize
@retval TRUE Single signed section found.
@retval FALSE Unsigned section found.
**/
BOOLEAN
HasSingleSignedFile (
IN VOID *FvStart,
IN UINT64 FvSize
)
{
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
EFI_FFS_FILE_HEADER *FfsHeader;
UINTN FfsSize;
BOOLEAN FindSignFile;
UINTN TestLength;
DEBUG ((DEBUG_INFO, "HasSingleSignedFile - FV: 0x%08x - 0x%08x\n", (UINTN)FvStart, (UINTN)FvSize));
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvStart;
//
// FvHeader
//
DEBUG ((DEBUG_INFO, " FileSystemGuid = 0x%g\n", &FvHeader->FileSystemGuid));
DEBUG ((DEBUG_INFO, " FvLength = 0x%X\n", FvHeader->FvLength));
DEBUG ((DEBUG_INFO, " FvHeader Size = 0x%X\n", FvHeader->HeaderLength));
if (FvHeader->FvLength != FvSize) {
DEBUG ((DEBUG_ERROR, "HasSingleSignedFile - FvSize: 0x%08x, expect - 0x%08x\n", (UINTN)FvHeader->FvLength, (UINTN)FvSize));
return FALSE;
}
//
// Find FFS
//
if (FvHeader->ExtHeaderOffset != 0) {
FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FvHeader + FvHeader->ExtHeaderOffset);
FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize);
} else {
FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength);
}
FfsHeader = (EFI_FFS_FILE_HEADER *)ALIGN_POINTER(FfsHeader, 8);
FindSignFile = FALSE;
while ((UINTN)FfsHeader < (UINTN)FvStart + FvSize) {
DEBUG ((DEBUG_INFO, "HasSingleSignedFile - FFS: 0x%08x\n", FfsHeader));
DEBUG ((DEBUG_INFO, " Name = 0x%g\n", &FfsHeader->Name));
DEBUG ((DEBUG_INFO, " Type = 0x%X\n", FfsHeader->Type));
TestLength = (UINTN)((UINTN)FvStart + FvSize - (UINTN)FfsHeader);
if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
TestLength = sizeof (EFI_FFS_FILE_HEADER);
}
if (IsBufferErased (1, FfsHeader, TestLength)) {
break;
}
if (IS_FFS_FILE2 (FfsHeader)) {
FfsSize = FFS_FILE2_SIZE(FfsHeader);
} else {
FfsSize = FFS_FILE_SIZE(FfsHeader);
}
if (FfsHeader->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
//
// Check section
//
FindSignFile = HasSingleSignedSection (FfsHeader, FfsSize);
if (FindSignFile == FALSE) {
DEBUG ((DEBUG_ERROR, "HasSingleSignedFile - HasSingleSignedSection Failed\n"));
return FALSE;
}
} else {
//
// Any other type is not allowed
//
DEBUG ((DEBUG_ERROR, "HasSingleSignedFile - invalid FFS type %x\n", FfsHeader->Type));
return FALSE;
}
//
// Next File
//
FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER ((UINTN)FfsHeader + FfsSize, 8);
}
return FindSignFile;
}
/**
@param[in] BiosInfoHeader
@retval TRUE POST Ibb is signed
@retval FALSE POST Ibb is not signed
**/
BOOLEAN
IsPostIbbSigned (
IN BIOS_INFO_HEADER *BiosInfoHeader
)
{
BOOLEAN FinalResult;
BOOLEAN Result;
BIOS_INFO_STRUCT *BiosInfoStruct;
UINTN Index;
DEBUG ((DEBUG_INFO, "IsPostIbbSigned Entry\n"));
FinalResult = TRUE;
BiosInfoStruct = (BIOS_INFO_STRUCT *)(BiosInfoHeader + 1);
for (Index = 0; Index < BiosInfoHeader->EntryCount; Index++) {
if (BiosInfoStruct[Index].Type != FIT_TABLE_TYPE_BIOS_MODULE) {
continue;
}
if ((BiosInfoStruct[Index].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB) != 0) {
Result = HasSingleSignedFile ((VOID *)(UINTN)BiosInfoStruct[Index].Address, BiosInfoStruct[Index].Size);
if (!Result) {
FinalResult = FALSE;
}
}
}
DEBUG ((DEBUG_INFO, "IsPostIbbSigned Exit\n"));
return FinalResult;
}
/**
Checks BiosInfo Ppi.
@param[in] FileHandle Handle of the file being invoked.
@param[in] PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS Boot mode is S3, Recovery or Post Ibb is verified signed
@retval FALSE Failed to locate gBiosInfoGuid Ppi
@retval None May enter CpuDeadLoop() if Post Ibb is not signed
**/
EFI_STATUS
EFIAPI
BiosInfoCheckerEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
BIOS_INFO_HEADER *BiosInfoHeader;
BOOLEAN Result;
EFI_BOOT_MODE BootMode;
DEBUG ((DEBUG_INFO, "BiosInfoCheckerEntryPoint Entry "));
Status = PeiServicesGetBootMode (&BootMode);
ASSERT_EFI_ERROR (Status);
if (BootMode == BOOT_IN_RECOVERY_MODE) {
// Do not check RECOVERY, because we do not trust flash region.
DEBUG ((DEBUG_INFO, "BiosInfoChecker skipped in Recovery boot path\n"));
return EFI_SUCCESS;
}
Status = PeiServicesLocatePpi (
&gBiosInfoGuid,
0,
NULL,
(VOID **)&BiosInfoHeader
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "BiosInfoChecker skipped due to BioInfo PPI not found\n"));
return EFI_NOT_FOUND;
}
//
// EnforcePolicy
//
if (PcdGetBool (PcdPostIbbVerificationEnable)) {
Result = IsPostIbbSigned (BiosInfoHeader);
if (!Result) {
//
// TBD: Need set recovery mode? or just reset system?
// Or check VerifiedBoot/MeasuredBoot policy?
//
ASSERT (FALSE);
CpuDeadLoop ();
}
} else {
DEBUG ((DEBUG_INFO, "Warning: BiosInfoChecker skipped.\n"));
}
DEBUG ((DEBUG_INFO, "BiosInfoCheckerEntryPoint Exit\n"));
return EFI_SUCCESS;
}