X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FVariable%2FRuntimeDxe%2FVariable.c;h=fca8d5380924449533b19572fef040d2d8ec9b60;hp=969df955181e415fcd6cc90bdbcb1a69010f9927;hb=09808bd39b0c76559354253639766458ec24da79;hpb=a0460be7e88539649cd10139491dd6955c54fb14 diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index 969df95518..fca8d53809 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -16,8 +16,8 @@ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow, integer overflow. It should also check attribute to avoid authentication bypass. -Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+(C) Copyright 2015-2018 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 which accompanies this distribution. The full text of the license may be found at @@ -238,6 +238,8 @@ IsValidVariableHeader ( @param Buffer Pointer to the buffer from which data is written. @retval EFI_INVALID_PARAMETER Parameters not valid. + @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update. + @retval EFI_OUT_OF_RESOURCES The remaining size is not enough. @retval EFI_SUCCESS Variable store successfully updated. **/ @@ -274,7 +276,7 @@ UpdateVariableStore ( // if (!Volatile) { if (Fvb == NULL) { - return EFI_INVALID_PARAMETER; + return EFI_UNSUPPORTED; } Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); ASSERT_EFI_ERROR (Status); @@ -288,8 +290,8 @@ UpdateVariableStore ( DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; } - if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) { - return EFI_INVALID_PARAMETER; + if ((DataPtr + DataSize) > ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) { + return EFI_OUT_OF_RESOURCES; } } else { // @@ -301,8 +303,8 @@ UpdateVariableStore ( DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; } - if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) { - return EFI_INVALID_PARAMETER; + if ((DataPtr + DataSize) > ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) { + return EFI_OUT_OF_RESOURCES; } // @@ -1531,8 +1533,8 @@ GetLangFromSupportedLangCodes ( @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that contains a set of language codes in the format specified by Iso639Language. - @param[in] Iso639Language If TRUE, then all language codes are assumed to be - in ISO 639-2 format. If FALSE, then all language + @param[in] Iso639Language If not zero, then all language codes are assumed to be + in ISO 639-2 format. If zero, then all language codes are assumed to be in RFC 4646 language format @param[in] ... A variable argument list that contains pointers to Null-terminated ASCII strings that contain one or more @@ -1560,7 +1562,7 @@ CHAR8 * EFIAPI VariableGetBestLanguage ( IN CONST CHAR8 *SupportedLanguages, - IN BOOLEAN Iso639Language, + IN UINTN Iso639Language, ... ) { @@ -1586,7 +1588,7 @@ VariableGetBestLanguage ( // // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language // - if (!Iso639Language) { + if (Iso639Language == 0) { for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++); } @@ -1601,7 +1603,7 @@ VariableGetBestLanguage ( // // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages // - if (!Iso639Language) { + if (Iso639Language == 0) { // // Skip ';' characters in Supported // @@ -1623,13 +1625,13 @@ VariableGetBestLanguage ( if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) { VA_END (Args); - Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang; + Buffer = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang; Buffer[CompareLength] = '\0'; return CopyMem (Buffer, Supported, CompareLength); } } - if (Iso639Language) { + if (Iso639Language != 0) { // // If ISO 639 mode, then each language can only be tested once // @@ -2345,12 +2347,14 @@ UpdateVariable ( CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr)); // - // Set Max Common/Auth Variable Data Size as default MaxDataSize. + // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize. // if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset; - } else { + } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset; + } else { + MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset; } // @@ -3146,7 +3150,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) { // @@ -3169,15 +3177,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) { @@ -3213,16 +3222,20 @@ VariableServiceSetVariable ( } else { // // The size of the VariableName, including the Unicode Null in bytes plus - // the DataSize is limited to maximum size of Max(Auth)VariableSize bytes. + // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes. // if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) { return EFI_INVALID_PARAMETER; } - } else { + } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) { return EFI_INVALID_PARAMETER; } + } else { + if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ()) { + return EFI_INVALID_PARAMETER; + } } } @@ -3394,12 +3407,14 @@ VariableServiceQueryVariableInfoInternal ( } // - // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size. + // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size. // if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize (); - } else { + } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (); + } else { + *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize (); } } @@ -3523,6 +3538,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. @@ -3645,6 +3667,30 @@ GetNonVolatileMaxVariableSize ( } } +/** + Get maximum variable size, covering both non-volatile and volatile variables. + + @return Maximum variable size. + +**/ +UINTN +GetMaxVariableSize ( + VOID + ) +{ + UINTN MaxVariableSize; + + MaxVariableSize = GetNonVolatileMaxVariableSize(); + // + // The condition below fails implicitly if PcdMaxVolatileVariableSize equals + // the default zero value. + // + if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) { + MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize); + } + return MaxVariableSize; +} + /** Init non-volatile variable store. @@ -4024,6 +4070,162 @@ 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)AuthStartPtr - (UINTN)AuthVarStorage); + CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid); + ASSERT (AuthVarStorage->Size <= AuthVarStroageSize); + + // + // Restore AuthFormat + // + mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE; + return AuthVarStorage; +} + +/** + Get HOB variable store. + + @param[out] VariableGuid NV variable store signature. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +GetHobVariableStore ( + IN EFI_GUID *VariableGuid + ) +{ + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINT64 VariableStoreLength; + EFI_HOB_GUID_TYPE *GuidHob; + BOOLEAN NeedConvertNormalToAuth; + + // + // Combinations supported: + // 1. Normal NV variable store + + // Normal HOB variable store + // 2. Auth NV variable store + + // Auth HOB variable store + // 3. Auth NV variable store + + // Normal HOB variable store (code will convert it to Auth Format) + // + NeedConvertNormalToAuth = FALSE; + GuidHob = GetFirstGuidHob (VariableGuid); + if (GuidHob == NULL && VariableGuid == &gEfiAuthenticatedVariableGuid) { + // + // Try getting it from normal variable HOB + // + GuidHob = GetFirstGuidHob (&gEfiVariableGuid); + NeedConvertNormalToAuth = TRUE; + } + if (GuidHob != NULL) { + VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob); + VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE); + if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { + if (!NeedConvertNormalToAuth) { + 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) { + return EFI_OUT_OF_RESOURCES; + } + } else { + DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n")); + } + } + + return EFI_SUCCESS; +} /** Initializes variable store area for non-volatile and volatile variable. @@ -4039,10 +4241,7 @@ VariableCommonInitialize ( { EFI_STATUS Status; VARIABLE_STORE_HEADER *VolatileVariableStore; - VARIABLE_STORE_HEADER *VariableStoreHeader; - UINT64 VariableStoreLength; UINTN ScratchSize; - EFI_HOB_GUID_TYPE *GuidHob; EFI_GUID *VariableGuid; EFI_FIRMWARE_VOLUME_HEADER *NvFvHeader; @@ -4086,26 +4285,21 @@ VariableCommonInitialize ( // // Get HOB variable store. // - GuidHob = GetFirstGuidHob (VariableGuid); - if (GuidHob != NULL) { - VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob); - 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 (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) { - FreePool (NvFvHeader); - FreePool (mVariableModuleGlobal); - return EFI_OUT_OF_RESOURCES; - } - } else { - DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n")); - } + Status = GetHobVariableStore (VariableGuid); + if (EFI_ERROR (Status)) { + FreePool (NvFvHeader); + FreePool (mVariableModuleGlobal); + return Status; } + mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ? + PcdGet32 (PcdMaxVolatileVariableSize) : + mVariableModuleGlobal->MaxVariableSize + ); // // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data. // - ScratchSize = GetNonVolatileMaxVariableSize (); + ScratchSize = GetMaxVariableSize (); mVariableModuleGlobal->ScratchBufferSize = ScratchSize; VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize); if (VolatileVariableStore == NULL) {