From 1ed4dbb91fb42787f8e1aabc33cde6b6c35670f3 Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Mon, 26 Jun 2017 11:31:41 +0800 Subject: Security of Setup Variable System can still boot to shell and OS successfully after EFI variable deletion/corruption. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- Platform/BroxtonPlatformPkg/BuildBios.bat | 11 +- .../PlatformPreMemPei/MultiPlatSupport.h | 201 ++++++++++++++++++++ .../PlatformPreMemPei/PlatformInitPreMem.c | 207 +++++++++++++++++++++ .../PlatformPreMemPei/PlatformInitPreMem.h | 4 + .../PlatformSetupDxe/PlatformSetupDxe.c | 38 ++++ .../PlatformSettings/PlatformSetupDxe/Vfr.vfr | 10 +- 6 files changed, 465 insertions(+), 6 deletions(-) create mode 100644 Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/MultiPlatSupport.h (limited to 'Platform/BroxtonPlatformPkg') diff --git a/Platform/BroxtonPlatformPkg/BuildBios.bat b/Platform/BroxtonPlatformPkg/BuildBios.bat index f656876c21..2ecc28d6bc 100644 --- a/Platform/BroxtonPlatformPkg/BuildBios.bat +++ b/Platform/BroxtonPlatformPkg/BuildBios.bat @@ -387,10 +387,15 @@ if not exist "%AutoGenPath%" ( findstr /L "_PCD_VALUE_" %AutoGenPath% > %STITCH_PATH%\FlashMap.h echo Running FCE... +copy /b %BUILD_PATH%\FV\FvIBBM.fv + /b %BUILD_PATH%\FV\Soc.fd /b %BUILD_PATH%\FV\Temp.fd :: Extract Hii data from build and store a copy in HiiDefaultData.txt -fce.exe read -i %BUILD_PATH%\FV\Soc.fd > %BUILD_PATH%\FV\HiiDefaultData.txt 2>>EDK2.log +:: UQI 0006 005C 0078 0030 0031 0030 0031 is for question prompt(STR_IPU_ENABLED) +:: First 0006 is the length of string; Next six byte values are mapped to STR_IPU_ENABLED string value defined in Platform\BroxtonPlatformPkg\Common\PlatformSettings\PlatformSetupDxe\VfrStrings.uni. +fce.exe read -i %BUILD_PATH%\FV\Temp.fd 0006 005C 0078 0030 0031 0030 0031 > %BUILD_PATH%\FV\HiiDefaultData.txt 2>>EDK2.log :: Generate the Setup variable and save changes to BxtXXX.fd -fce.exe update -i %BUILD_PATH%\FV\Soc.fd -s %BUILD_PATH%\FV\HiiDefaultData.txt -o %BUILD_PATH%\FV\Bxt%Arch%.fd 1>>EDK2.log 2>&1 +:: B73FE497-B92E-416e-8326-45AD0D270091 is the GUID of IBBM FV +fce.exe update -i %BUILD_PATH%\FV\Temp.fd -s %BUILD_PATH%\FV\HiiDefaultData.txt -o %BUILD_PATH%\FV\Bxt%Arch%.fd -g B73FE497-B92E-416e-8326-45AD0D270091 -a 1>>EDK2.log 2>&1 +split -f %BUILD_PATH%\FV\Bxt%Arch%.fd -s 0x35000 -o %BUILD_PATH%\FV\FvIBBM.fv if ErrorLevel 1 goto BldFail @@ -401,7 +406,7 @@ if "%BUILD_TYPE%"=="R" set BUILD_TYPE=R echo Copy BIOS... set BIOS_Name=%BOARD_ID%_%Arch%_%BUILD_TYPE%_%VERSION_MAJOR%_%VERSION_MINOR% -copy /y/b %BUILD_PATH%\FV\Bxt%Arch%.fd %STITCH_PATH%\%BIOS_Name%.ROM >nul +copy /y/b %BUILD_PATH%\FV\Soc.fd %STITCH_PATH%\%BIOS_Name%.ROM >nul copy /y %STITCH_PATH%\FlashMap.h %STITCH_PATH%\%BIOS_Name%.map >nul set Storage_Folder=%STITCH_PATH%\%BIOS_Name% diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/MultiPlatSupport.h b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/MultiPlatSupport.h new file mode 100644 index 0000000000..7f21da28ff --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/MultiPlatSupport.h @@ -0,0 +1,201 @@ +/**@file + +Copyright (c) 2016 - 2017, 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. + +**/ + +#ifndef __MULTI_PLATFORM_SUPPORT_H__ +#define __MULTI_PLATFORM_SUPPORT_H__ + +extern EFI_GUID gDefaultDataOptSizeFileGuid; + +/// +/// Alignment of variable name and data, according to the architecture: +/// * For IA-32 and Intel(R) 64 architectures: 1. +/// * For IA-64 architecture: 8. +/// +#if defined (MDE_CPU_IPF) +#define ALIGNMENT 8 +#else +#define ALIGNMENT 1 +#endif + +// +// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement. +// +#if (ALIGNMENT == 1) +#define GET_PAD_SIZE(a) (0) +#else +#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1)) +#endif + +/// +/// Alignment of Variable Data Header in Variable Store region. +/// +#define HEADER_ALIGNMENT 4 +#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1))) + +/// +/// Status of Variable Store Region. +/// +/*typedef enum { + EfiRaw, + EfiValid, + EfiInvalid, + EfiUnknown +} VARIABLE_STORE_STATUS;*/ + +#pragma pack(1) + +/// +/// Variable Store Header Format and State. +/// +#define VARIABLE_STORE_FORMATTED 0x5a +#define VARIABLE_STORE_HEALTHY 0xfe + +/// +/// Variable Store region header. +/// +/*typedef struct { + /// + /// Variable store region signature. + /// + EFI_GUID Signature; + /// + /// Size of entire variable store, + /// including size of variable store header but not including the size of FvHeader. + /// + UINT32 Size; + /// + /// Variable region format state. + /// + UINT8 Format; + /// + /// Variable region healthy state. + /// + UINT8 State; + UINT16 Reserved; + UINT32 Reserved1; +} VARIABLE_STORE_HEADER;*/ + +/// +/// Variable data start flag. +/// +#define VARIABLE_DATA 0x55AA + +/// +/// Variable State flags. +/// +#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition. +#define VAR_DELETED 0xfd ///< Variable is obsolete. +#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid. +#define VAR_ADDED 0x3f ///< Variable has been completely added. + +/// +/// Single Variable Data Header Structure. +/// +/*typedef struct { + /// + /// Variable Data Start Flag. + /// + UINT16 StartId; + /// + /// Variable State defined above. + /// + UINT8 State; + UINT8 Reserved; + /// + /// Attributes of variable defined in UEFI specification. + /// + UINT32 Attributes; + /// + /// Size of variable null-terminated Unicode string name. + /// + UINT32 NameSize; + /// + /// Size of the variable data without this header. + /// + UINT32 DataSize; + /// + /// A unique identifier for the vendor that produces and consumes this varaible. + /// + EFI_GUID VendorGuid; +} VARIABLE_HEADER;*/ + +/// +/// Single Variable Data Header Structure for Auth variable. +/// +/*typedef struct { + /// + /// Variable Data Start Flag. + /// + UINT16 StartId; + /// + /// Variable State defined above. + /// + UINT8 State; + UINT8 Reserved; + /// + /// Attributes of variable defined in UEFI specification. + /// + UINT32 Attributes; + /// + /// Associated monotonic count value against replay attack. + /// + UINT64 MonotonicCount; + /// + /// Associated TimeStamp value against replay attack. + /// + EFI_TIME TimeStamp; + /// + /// Index of associated public key in database. + /// + UINT32 PubKeyIndex; + /// + /// Size of variable null-terminated Unicode string name. + /// + UINT32 NameSize; + /// + /// Size of the variable data without this header. + /// + UINT32 DataSize; + /// + /// A unique identifier for the vendor that produces and consumes this varaible. + /// + EFI_GUID VendorGuid; +} AUTHENTICATED_VARIABLE_HEADER;*/ + +typedef struct { + UINT16 DefaultId; + UINT16 BoardId; +} DEFAULT_INFO; + +typedef struct { + UINT16 Offset; + UINT8 Value; +} DATA_DELTA; + +typedef struct { + // + // HeaderSize includes HeaderSize fields and DefaultInfo arrays + // + UINT16 HeaderSize; + // + // DefaultInfo arrays those have the same default setting. + // + DEFAULT_INFO DefaultInfo[1]; + // + // Default data is stored as variable storage or the array of DATA_DELTA. + // +} DEFAULT_DATA; + +#pragma pack() + +#endif diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.c b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.c index fe454bf89f..49121aed7d 100644 --- a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.c +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.c @@ -75,6 +75,15 @@ #include #include +#include +#include +#include + +// +// GUID used in FCE. FCE generate ffs file with this GUID. +// +EFI_GUID gDefaultDataOptSizeFileGuid = { 0x003e7b41, 0x98a2, 0x4be2, { 0xb2, 0x7a, 0x6c, 0x30, 0xc7, 0x65, 0x52, 0x25 }}; + #if (ENBDT_PF_ENABLE == 1) // //SSC @@ -913,6 +922,7 @@ PlatformInitPreMemEntryPoint ( PEI_BOARD_PRE_MEM_INIT_PPI *BoardPreMemInitPpi; UINTN Instance; UINT64 AcpiVariableSetCompatibility; + UINTN VarSize; Status = (*PeiServices)->RegisterForShadow (FileHandle); @@ -1116,6 +1126,29 @@ PlatformInitPreMemEntryPoint ( Tick = CarMap->IbblPerfRecord4; PERF_END_EX (NULL, "IBBMVer", "IBBL", Tick, 0x1041); + + VarSize = sizeof (SYSTEM_CONFIGURATION); + Status = VariableServices->GetVariable ( + VariableServices, + L"Setup", + &gEfiSetupVariableGuid, + NULL, + &VarSize, + &SystemConfiguration + ); + if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) { + Status = PlatformCreateDefaultVariableHob (EFI_HII_DEFAULT_CLASS_STANDARD); + ASSERT_EFI_ERROR (Status); + } + Status = VariableServices->GetVariable ( + VariableServices, + L"Setup", + &gEfiSetupVariableGuid, + NULL, + &VarSize, + &SystemConfiguration + ); + ASSERT_EFI_ERROR (Status); // // Normal boot - build Hob for SEC performance data. // @@ -1372,3 +1405,177 @@ ReadBxtIPlatformIds ( return EFI_SUCCESS; } + +/** +Description: + + This function finds the matched default data and create GUID hob for it. + +Arguments: + + DefaultId - Specifies the type of defaults to retrieve. + +Returns: + + EFI_SUCCESS - The matched default data is found. + EFI_NOT_FOUND - The matched default data is not found. + EFI_OUT_OF_RESOURCES - No enough resource to create HOB. + +**/ +EFI_STATUS +PlatformCreateDefaultVariableHob ( + IN UINT16 DefaultId + ) + +{ + UINTN FvInstance; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FFS_FILE_HEADER *FfsHeader; + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + UINT32 SectionLength; + BOOLEAN DefaultSettingIsFound; + DEFAULT_DATA *DefaultData; + DEFAULT_INFO *DefaultInfo; + VARIABLE_STORE_HEADER *VarStoreHeader; + VARIABLE_STORE_HEADER *VarStoreHeaderHob; + UINT8 *VarHobPtr; + UINT8 *VarPtr; + UINT32 VarDataOffset; + UINT32 VarHobDataOffset; + BOOLEAN IsFirstSection; + DATA_DELTA *DataDelta; + UINTN DataDeltaSize; + UINTN Index; + CONST EFI_PEI_SERVICES **PeiServices; + + // + // Get PeiService pointer + // + PeiServices = GetPeiServicesTablePointer (); + + // + // Find the FFS file that stores all default data. + // + DefaultSettingIsFound = FALSE; + FvInstance = 0; + FfsHeader = NULL; + while (((*PeiServices)->FfsFindNextVolume (PeiServices, FvInstance, (VOID **) &FvHeader) == EFI_SUCCESS) && + (!DefaultSettingIsFound)) { + FfsHeader = NULL; + while ((*PeiServices)->FfsFindNextFile (PeiServices, EFI_FV_FILETYPE_FREEFORM, FvHeader, (VOID **) &FfsHeader) == EFI_SUCCESS) { + if (CompareGuid ((EFI_GUID *) FfsHeader, &gDefaultDataOptSizeFileGuid)) { + DefaultSettingIsFound = TRUE; + break; + } + } + FvInstance ++; + } + + // + // FFS file is not found. + // + if (!DefaultSettingIsFound) { + return EFI_NOT_FOUND; + } + + // + // Find the matched default data for the input default ID and plat ID. + // + DefaultSettingIsFound = FALSE; + VarStoreHeaderHob = NULL; + VarHobPtr = NULL; + DataDelta = NULL; + DataDeltaSize = 0; + IsFirstSection = TRUE; + VarStoreHeader = NULL; + Section = (EFI_COMMON_SECTION_HEADER *)(FfsHeader + 1); + FileSize = *(UINT32 *)(FfsHeader->Size) & 0x00FFFFFF; + while (((UINTN) Section < (UINTN) FfsHeader + FileSize) && !DefaultSettingIsFound) { + DefaultData = (DEFAULT_DATA *) (Section + 1); + DefaultInfo = &(DefaultData->DefaultInfo[0]); + SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; + + if (IsFirstSection) { + // + // Create HOB to store default data so that Variable driver can use it. + // Allocate more data for header alignment. + // + VarStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) DefaultData + DefaultData->HeaderSize); + VarStoreHeaderHob = (VARIABLE_STORE_HEADER *) BuildGuidHob (&VarStoreHeader->Signature, VarStoreHeader->Size + HEADER_ALIGNMENT - 1); + if (VarStoreHeaderHob == NULL) { + // + // No enough hob resource. + // + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy variable storage header. + // + CopyMem (VarStoreHeaderHob, VarStoreHeader, sizeof (VARIABLE_STORE_HEADER)); + // + // Copy variable data. + // + VarPtr = (UINT8 *) HEADER_ALIGN ((UINTN) (VarStoreHeader + 1)); + VarDataOffset = (UINT32) ((UINTN) VarPtr - (UINTN) VarStoreHeader); + VarHobPtr = (UINT8 *) HEADER_ALIGN ((UINTN) (VarStoreHeaderHob + 1)); + VarHobDataOffset = (UINT32) ((UINTN) VarHobPtr - (UINTN) VarStoreHeaderHob); + CopyMem (VarHobPtr, VarPtr, VarStoreHeader->Size - VarDataOffset); + // + // Update variable size. + // + VarStoreHeaderHob->Size = VarStoreHeader->Size - VarDataOffset + VarHobDataOffset; + + // + // Update Delta Data + // + VarHobPtr = (UINT8 *) VarStoreHeaderHob - VarDataOffset + VarHobDataOffset; + } else { + // + // Apply delta setting + // + DataDelta = (DATA_DELTA *) ((UINT8 *) DefaultData + DefaultData->HeaderSize); + DataDeltaSize = SectionLength - sizeof (EFI_COMMON_SECTION_HEADER) - DefaultData->HeaderSize; + for (Index = 0; Index < DataDeltaSize / sizeof (DATA_DELTA); Index ++) { + *((UINT8 *) VarHobPtr + DataDelta[Index].Offset) = DataDelta[Index].Value; + } + } + + // + // Find the matched DefaultId + // + while ((UINTN) DefaultInfo < (UINTN) DefaultData + DefaultData->HeaderSize) { + if (DefaultInfo->DefaultId == DefaultId) { + DefaultSettingIsFound = TRUE; + break; + } + DefaultInfo ++; + } + // + // Size is 24 bits wide so mask upper 8 bits. + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = (SectionLength + 3) & (~3); + ASSERT (SectionLength != 0); + Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); + IsFirstSection = FALSE; + } + // + // Matched default data is not found. + // + if (!DefaultSettingIsFound) { + // + // Change created HOB type to be unused. + // + if (VarStoreHeaderHob != NULL) { + ((EFI_HOB_GUID_TYPE *)((UINT8 *) VarStoreHeaderHob - sizeof (EFI_HOB_GUID_TYPE)))->Header.HobType = EFI_HOB_TYPE_UNUSED; + } + return EFI_NOT_FOUND; + } + + + return EFI_SUCCESS; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.h b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.h index 17b4dad36d..3aa5033e08 100644 --- a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.h +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformPreMemPei/PlatformInitPreMem.h @@ -139,5 +139,9 @@ InstallMonoStatusCode ( IN CONST EFI_PEI_SERVICES **PeiServices ); +EFI_STATUS +PlatformCreateDefaultVariableHob ( +IN UINT16 DefaultId +); #endif diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/PlatformSetupDxe.c b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/PlatformSetupDxe.c index 54c751faaf..ff594965f2 100644 --- a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/PlatformSetupDxe.c +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/PlatformSetupDxe.c @@ -402,6 +402,8 @@ SystemConfigCallback ( CHAR16 *StringBuffer2; EFI_STATUS Status; SEC_OPERATION_PROTOCOL *SeCOp; + UINTN VariableSize; + UINT32 VariableAttributes; StringBuffer1 = AllocateZeroPool (200 * sizeof (CHAR16)); ASSERT (StringBuffer1 != NULL); @@ -412,7 +414,43 @@ SystemConfigCallback ( return EFI_OUT_OF_RESOURCES; } + Private = EFI_CALLBACK_INFO_FROM_THIS (This); + FakeNvData = &Private->FakeNvData; + switch (Action) { + case EFI_BROWSER_ACTION_FORM_OPEN: + { + if (KeyValue == 0x1003) { + if (!HiiGetBrowserData (&mSystemConfigGuid, mVariableName, sizeof (SYSTEM_CONFIGURATION), (UINT8 *) FakeNvData)) { + return EFI_NOT_FOUND; + } + + CheckSystemConfigLoad (FakeNvData); + + // + // Pass changed uncommitted data back to Form Browser + // + HiiSetBrowserData (&mSystemConfigGuid, mVariableName, sizeof (SYSTEM_CONFIGURATION), (UINT8 *) FakeNvData, NULL); + } + break; + } + case EFI_BROWSER_ACTION_SUBMITTED: + { + if (KeyValue == 0x1002) { + VariableSize = sizeof (SYSTEM_CONFIGURATION); + Status = gRT->GetVariable ( + L"Setup", + &gEfiSetupVariableGuid, + &VariableAttributes, + &VariableSize, + FakeNvData + ); + if (!EFI_ERROR (Status)) { + CheckSystemConfigSave (FakeNvData); + } + } + break; + } case EFI_BROWSER_ACTION_CHANGING: case EFI_BROWSER_ACTION_CHANGED: { diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/Vfr.vfr b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/Vfr.vfr index 4b10a49bfe..5e5b4facb6 100644 --- a/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/Vfr.vfr +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSettings/PlatformSetupDxe/Vfr.vfr @@ -16,6 +16,9 @@ #include "PlatformSetupDxeStrDefs.h" #include "Guid/SetupVariable.h" +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 formset guid = SYSTEM_CONFIGURATION_GUID, @@ -24,8 +27,7 @@ formset class = 1, subclass = 0, - - varstore SYSTEM_CONFIGURATION, name = Setup, guid = SYSTEM_CONFIGURATION_GUID; + efivarstore SYSTEM_CONFIGURATION, attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS, name = Setup, guid = SYSTEM_CONFIGURATION_GUID; form formid = ROOT_FORM_ID, title = STRING_TOKEN(STR_SYSTEM_SETUP_TITLE); @@ -34,7 +36,9 @@ formset // goto ROOT_MAIN_FORM_ID, prompt = STRING_TOKEN(STR_MAIN_TITLE), - help = STRING_TOKEN(STR_MAIN_HELP); + help = STRING_TOKEN(STR_MAIN_HELP), + flags = INTERACTIVE, // INTERACTIVE indicate it's marked with EFI_IFR_FLAG_CALLBACK + key = 0x1003; // Question ID which will be passed-in in COnfigAccess.Callback() // // Jump to 2)CPU Configuration Form -- cgit v1.2.3