/** @file\r
- The common variable operation routines shared by DXE_RINTIME variable\r
+ The common variable operation routines shared by DXE_RUNTIME variable\r
module and DXE_SMM variable module.\r
\r
+ Caution: This module requires additional review when modified.\r
+ This driver will have external input - variable data. They may be input in SMM mode.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.\r
+ They need check input parameter.\r
+\r
+ VariableServiceGetVariable() and VariableServiceSetVariable() are external API\r
+ to receive datasize and data buffer. The size should be checked carefully.\r
+\r
+ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,\r
+ integer overflow. It should also check attribute to avoid authentication bypass.\r
+\r
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
EFI_STATUS Status;\r
CHAR16 *VariableNamePtr;\r
CHAR16 *UpdatingVariableNamePtr;\r
+ UINTN CommonVariableTotalSize;\r
+ UINTN HwErrVariableTotalSize;\r
\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
- //\r
- // Recalculate the total size of Common/HwErr type variables in non-volatile area.\r
- //\r
- if (!IsVolatile) {\r
- mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
- mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
- }\r
+\r
+ CommonVariableTotalSize = 0;\r
+ HwErrVariableTotalSize = 0;\r
\r
//\r
// Start Pointers for the variable.\r
CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
CurrPtr += VariableSize;\r
if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+ HwErrVariableTotalSize += VariableSize;\r
} else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ CommonVariableTotalSize += VariableSize;\r
}\r
}\r
Variable = NextVariable;\r
CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
CurrPtr += VariableSize;\r
if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+ HwErrVariableTotalSize += VariableSize;\r
} else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ CommonVariableTotalSize += VariableSize;\r
}\r
}\r
\r
((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
CurrPtr += VariableSize;\r
if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+ HwErrVariableTotalSize += VariableSize;\r
} else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ CommonVariableTotalSize += VariableSize;\r
}\r
}\r
}\r
}\r
if (!EFI_ERROR (Status)) {\r
*LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
+ if (!IsVolatile) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+ }\r
} else {\r
- *LastVariableOffset = 0;\r
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
+ while (IsValidVariableHeader (NextVariable)) {\r
+ VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ }\r
+\r
+ NextVariable = GetNextVariablePtr (NextVariable);\r
+ }\r
+ *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
}\r
\r
FreePool (ValidBuffer);\r
return Status;\r
}\r
\r
+/**\r
+ Check if a Unicode character is a hexadecimal character.\r
+\r
+ This function checks if a Unicode character is a \r
+ hexadecimal character. The valid hexadecimal character is \r
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
+\r
+\r
+ @param Char The character to check against.\r
+\r
+ @retval TRUE If the Char is a hexadecmial character.\r
+ @retval FALSE If the Char is not a hexadecmial character.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHexaDecimalDigitCharacter (\r
+ IN CHAR16 Char\r
+ )\r
+{\r
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
+}\r
+\r
+/**\r
+\r
+ This code checks if variable is hardware error record variable or not.\r
+\r
+ According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
+ and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
+\r
+ @param VariableName Pointer to variable name.\r
+ @param VendorGuid Variable Vendor Guid.\r
+\r
+ @retval TRUE Variable is hardware error record variable.\r
+ @retval FALSE Variable is not hardware error record variable.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHwErrRecVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
+ (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
+ (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ This code checks if variable should be treated as read-only variable.\r
+\r
+ @param[in] VariableName Name of the Variable.\r
+ @param[in] VendorGuid GUID of the Variable.\r
+\r
+ @retval TRUE This variable is read-only variable.\r
+ @retval FALSE This variable is NOT read-only variable.\r
+ \r
+**/\r
+BOOLEAN\r
+IsReadOnlyVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {\r
+ if ((StrCmp (VariableName, EFI_SETUP_MODE_NAME) == 0) ||\r
+ (StrCmp (VariableName, EFI_SIGNATURE_SUPPORT_NAME) == 0) ||\r
+ (StrCmp (VariableName, EFI_SECURE_BOOT_MODE_NAME) == 0)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
/**\r
\r
This code finds variable in storage blocks (Volatile or Non-Volatile).\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize is external input.\r
+ This function will do basic validation, before parse the data.\r
+\r
@param VariableName Name of Variable to be found.\r
@param VendorGuid Variable vendor GUID.\r
@param Attributes Attribute value of the variable found.\r
\r
This code Finds the Next available variable.\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
+\r
@param VariableNameSize Size of the variable name.\r
@param VariableName Pointer to variable name.\r
@param VendorGuid Variable Vendor Guid.\r
\r
This code sets variable in storage blocks (Volatile or Non-Volatile).\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize and data are external input.\r
+ This function will do basic validation, before parse the data.\r
+ This function will parse the authentication carefully to avoid security issues, like\r
+ buffer overflow, integer overflow.\r
+ This function will check attribute carefully to avoid authentication bypass.\r
+\r
@param VariableName Name of Variable to be found.\r
@param VendorGuid Variable vendor GUID.\r
@param Attributes Attribute value of the variable found\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if (IsReadOnlyVariable (VariableName, VendorGuid)) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
if (DataSize != 0 && Data == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
(sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- //\r
- // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".\r
- //\r
- if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
+ if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
} else {\r
}\r
}\r
\r
+ if (AtRuntime ()) {\r
+ //\r
+ // HwErrRecSupport Global Variable identifies the level of hardware error record persistence\r
+ // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.\r
+ //\r
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+ }\r
+\r
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
//\r
Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
} else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) {\r
- Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+ }\r
} else {\r
Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
}\r
\r
This code returns information about the EFI variables.\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
+\r
@param Attributes Attributes bitmask to specify the type of variables\r
on which to return information.\r
@param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
/**\r
This function reclaims variable storage if free size is below the threshold.\r
\r
+ Caution: This function may be invoked at SMM mode.\r
+ Care must be taken to make sure not security issue.\r
+\r
**/\r
VOID\r
ReclaimForOS(\r