X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FVariable%2FRuntimeDxe%2FVariable.c;h=77905a0a308086d3b7dc8acebc723dcaae159b4d;hp=3f0240bc072f6ef2e5bd4e7eacfb7ae6e09a8368;hb=a37044efba8c6b21c2d919f6ca306fcc69c1f59d;hpb=dd59d95e1994c3d4dde7a0d5503109db1d207bea diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index 3f0240bc07..77905a0a30 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -16,7 +16,7 @@ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow, integer overflow. It should also check attribute to avoid authentication bypass. -Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
(C) Copyright 2015 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -97,57 +97,6 @@ AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = { AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut; -/** - - SecureBoot Hook for auth variable update. - - @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 - ); - -/** - Initialization for MOR Lock Control. - - @retval EFI_SUCEESS MorLock initialization success. - @return Others Some error occurs. -**/ -EFI_STATUS -MorLockInit ( - VOID - ); - -/** - This service is an MOR/MorLock checker handler for the SetVariable(). - - @param VariableName the name of the vendor's variable, as a - Null-Terminated Unicode String - @param VendorGuid Unify identifier for vendor. - @param Attributes Point to memory location to return the attributes of variable. If the point - is NULL, the parameter would be ignored. - @param DataSize The size in bytes of Data-Buffer. - @param Data Point to the content of the variable. - - @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable driver can store the variable data. - @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or attributes is not allowed for MOR variable. - @retval EFI_ACCESS_DENIED The MOR/MorLock is locked. - @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function. - Variable driver can just return EFI_SUCCESS. -**/ -EFI_STATUS -SetVariableCheckHandlerMor ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - IN UINT32 Attributes, - IN UINTN DataSize, - IN VOID *Data - ); - /** Routine used to track statistical information about variable usage. The data is stored in the EFI system table so it can be accessed later. @@ -1170,7 +1119,7 @@ Reclaim ( // Install the new variable if it is not NULL. // if (NewVariable != NULL) { - if ((UINTN) (CurrPtr - ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) { + if (((UINTN) CurrPtr - (UINTN) ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) { // // No enough space to store the new variable. // @@ -1211,8 +1160,8 @@ Reclaim ( // If volatile variable store, just copy valid buffer. // SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff); - CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - ValidBuffer)); - *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer); + CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer); + *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer; Status = EFI_SUCCESS; } else { // @@ -1223,7 +1172,7 @@ Reclaim ( (VARIABLE_STORE_HEADER *) ValidBuffer ); if (!EFI_ERROR (Status)) { - *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer); + *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer; mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize; mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize; mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize; @@ -1771,6 +1720,7 @@ CheckRemainingSpaceForConsistencyInternal ( TotalNeededSize += VariableEntry->VariableSize; VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); } + VA_END (Args); if (RemainingVariableStorageSize >= TotalNeededSize) { // @@ -1815,6 +1765,7 @@ CheckRemainingSpaceForConsistencyInternal ( // // No enough space for Variable[Index]. // + VA_END (Args); return FALSE; } // @@ -1823,6 +1774,7 @@ CheckRemainingSpaceForConsistencyInternal ( RemainingVariableStorageSize -= VariableEntry->VariableSize; VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); } + VA_END (Args); return TRUE; } @@ -2849,6 +2801,10 @@ VariableServiceGetVariable ( return EFI_INVALID_PARAMETER; } + if (VariableName[0] == 0) { + return EFI_NOT_FOUND; + } + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); @@ -2899,8 +2855,11 @@ Done: @param[in] VendorGuid Variable Vendor Guid. @param[out] VariablePtr Pointer to variable header address. - @return EFI_SUCCESS Find the specified variable. - @return EFI_NOT_FOUND Not found. + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and + GUID of an existing variable. **/ EFI_STATUS @@ -2920,6 +2879,19 @@ VariableServiceGetNextVariableInternal ( Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + // + // For VariableName is an empty string, FindVariable() will try to find and return + // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND) + // as no any variable is found, still go to return the error (EFI_NOT_FOUND). + // + if (VariableName[0] != 0) { + // + // For VariableName is not an empty string, and FindVariable() returns error as + // VariableName and VendorGuid are not a name and GUID of an existing variable, + // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER. + // + Status = EFI_INVALID_PARAMETER; + } goto Done; } @@ -3040,14 +3012,22 @@ Done: Caution: This function may receive untrusted input. This function may be invoked in SMM mode. This function will do basic validation, before parse the data. - @param VariableNameSize Size of the variable name. + @param VariableNameSize The size of the VariableName buffer. The size must be large + enough to fit input string supplied in VariableName buffer. @param VariableName Pointer to variable name. @param VendorGuid Variable Vendor Guid. - @return EFI_INVALID_PARAMETER Invalid parameter. - @return EFI_SUCCESS Find the specified variable. - @return EFI_NOT_FOUND Not found. - @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result. + VariableNameSize has been updated with the size needed to complete the request. + @retval EFI_INVALID_PARAMETER VariableNameSize is NULL. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and + GUID of an existing variable. + @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of + the input VariableName buffer. **/ EFI_STATUS @@ -3059,6 +3039,7 @@ VariableServiceGetNextVariableName ( ) { EFI_STATUS Status; + UINTN MaxLen; UINTN VarNameSize; VARIABLE_HEADER *VariablePtr; @@ -3066,6 +3047,18 @@ VariableServiceGetNextVariableName ( return EFI_INVALID_PARAMETER; } + // + // Calculate the possible maximum length of name string, including the Null terminator. + // + MaxLen = *VariableNameSize / sizeof (CHAR16); + if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) { + // + // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer, + // follow spec to return EFI_INVALID_PARAMETER. + // + return EFI_INVALID_PARAMETER; + } + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); Status = VariableServiceGetNextVariableInternal (VariableName, VendorGuid, &VariablePtr); @@ -3141,8 +3134,11 @@ VariableServiceSetVariable ( // // Check for reserverd bit in variable attribute. + // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow + // the delete operation of common authenticated variable at user physical presence. + // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib // - if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) { + if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) { return EFI_INVALID_PARAMETER; } @@ -3150,7 +3146,11 @@ VariableServiceSetVariable ( // Make sure if runtime bit is set, boot service bit is set also. // if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { - return EFI_INVALID_PARAMETER; + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + return EFI_UNSUPPORTED; + } else { + return EFI_INVALID_PARAMETER; + } } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) { // @@ -3173,15 +3173,16 @@ VariableServiceSetVariable ( // if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { - return EFI_INVALID_PARAMETER; + return EFI_UNSUPPORTED; } if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { - if (DataSize < AUTHINFO_SIZE) { - // - // Try to write Authenticated Variable without AuthInfo. - // - return EFI_SECURITY_VIOLATION; + // + // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0. + // Maybe it's the delete operation of common authenticated variable at user physical presence. + // + if (DataSize != AUTHINFO_SIZE) { + return EFI_UNSUPPORTED; } PayloadSize = DataSize - AUTHINFO_SIZE; } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { @@ -3527,6 +3528,13 @@ VariableServiceQueryVariableInfo ( return EFI_INVALID_PARAMETER; } + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // Deprecated attribute, make this check as highest priority. + // + return EFI_UNSUPPORTED; + } + if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) { // // Make sure the Attributes combination is supported by the platform. @@ -3748,8 +3756,8 @@ InitNonVolatileVariableStore ( return EFI_VOLUME_CORRUPTED; } - VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength); - VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength); + VariableStoreBase = (UINTN) FvHeader + FvHeader->HeaderLength; + VariableStoreLength = NvStorageSize - FvHeader->HeaderLength; mNvFvHeaderCache = FvHeader; mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; @@ -4011,7 +4019,7 @@ VariableWriteServiceInitialize ( } if (!EFI_ERROR (Status)) { - for (Index = 0; Index < sizeof (mVariableEntryProperty) / sizeof (mVariableEntryProperty[0]); Index++) { + for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) { VariableEntry = &mVariableEntryProperty[Index]; Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty); ASSERT_EFI_ERROR (Status); @@ -4028,7 +4036,105 @@ VariableWriteServiceInitialize ( return Status; } +/** + Convert normal variable storage to the allocated auth variable storage. + + @param[in] NormalVarStorage Pointer to the normal variable storage header + + @retval the allocated auth variable storage +**/ +VOID * +ConvertNormalVarStorageToAuthVarStorage ( + VARIABLE_STORE_HEADER *NormalVarStorage + ) +{ + VARIABLE_HEADER *StartPtr; + UINT8 *NextPtr; + VARIABLE_HEADER *EndPtr; + UINTN AuthVarStroageSize; + AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr; + VARIABLE_STORE_HEADER *AuthVarStorage; + + AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER); + // + // Set AuthFormat as FALSE for normal variable storage + // + mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE; + + // + // Calculate Auth Variable Storage Size + // + StartPtr = GetStartPointer (NormalVarStorage); + EndPtr = GetEndPointer (NormalVarStorage); + while (StartPtr < EndPtr) { + if (StartPtr->State == VAR_ADDED) { + AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize); + AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER); + AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize); + AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize); + } + StartPtr = GetNextVariablePtr (StartPtr); + } + + // + // Allocate Runtime memory for Auth Variable Storage + // + AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize); + ASSERT (AuthVarStorage != NULL); + if (AuthVarStorage == NULL) { + return NULL; + } + + // + // Copy Variable from Normal storage to Auth storage + // + StartPtr = GetStartPointer (NormalVarStorage); + EndPtr = GetEndPointer (NormalVarStorage); + AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) GetStartPointer (AuthVarStorage); + while (StartPtr < EndPtr) { + if (StartPtr->State == VAR_ADDED) { + AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (AuthStartPtr); + // + // Copy Variable Header + // + AuthStartPtr->StartId = StartPtr->StartId; + AuthStartPtr->State = StartPtr->State; + AuthStartPtr->Attributes = StartPtr->Attributes; + AuthStartPtr->NameSize = StartPtr->NameSize; + AuthStartPtr->DataSize = StartPtr->DataSize; + CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid); + // + // Copy Variable Name + // + NextPtr = (UINT8 *) (AuthStartPtr + 1); + CopyMem (NextPtr, GetVariableNamePtr (StartPtr), AuthStartPtr->NameSize); + // + // Copy Variable Data + // + NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize); + CopyMem (NextPtr, GetVariableDataPtr (StartPtr), AuthStartPtr->DataSize); + // + // Go to next variable + // + AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) (NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize)); + } + StartPtr = GetNextVariablePtr (StartPtr); + } + // + // Update Auth Storage Header + // + AuthVarStorage->Format = NormalVarStorage->Format; + AuthVarStorage->State = NormalVarStorage->State; + AuthVarStorage->Size = (UINT32) (UINTN) ((UINT8 *) AuthStartPtr - (UINT8 *) AuthVarStorage); + CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid); + ASSERT (AuthVarStorage->Size <= AuthVarStroageSize); + // + // Restore AuthFormat + // + mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE; + return AuthVarStorage; +} /** Initializes variable store area for non-volatile and volatile variable. @@ -4049,6 +4155,7 @@ VariableCommonInitialize ( EFI_HOB_GUID_TYPE *GuidHob; EFI_GUID *VariableGuid; EFI_FIRMWARE_VOLUME_HEADER *NvFvHeader; + BOOLEAN IsNormalVariableHob; // // Allocate runtime memory for variable driver global structure. @@ -4090,12 +4197,24 @@ VariableCommonInitialize ( // // Get HOB variable store. // + IsNormalVariableHob = FALSE; GuidHob = GetFirstGuidHob (VariableGuid); + if (GuidHob == NULL && VariableGuid == &gEfiAuthenticatedVariableGuid) { + // + // Try getting it from normal variable HOB + // + GuidHob = GetFirstGuidHob (&gEfiVariableGuid); + IsNormalVariableHob = TRUE; + } if (GuidHob != NULL) { VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob); - VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE)); + VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE); if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { - mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader); + if (IsNormalVariableHob == FALSE) { + mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader); + } else { + mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ConvertNormalVarStorageToAuthVarStorage ((VOID *) VariableStoreHeader); + } if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) { FreePool (NvFvHeader); FreePool (mVariableModuleGlobal);