X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=SecurityPkg%2FVariableAuthenticated%2FRuntimeDxe%2FVariable.c;h=07fe99bee7e142bde76d258b8955a939ab641f19;hb=9b78227a252b629ae6752922333d26d0560b810a;hp=22ded16819077a34b5b1a7927fc751ca9c349a48;hpb=ecc722ad418a926af4e383f8977444717786fe20;p=mirror_edk2.git diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c index 22ded16819..07fe99bee7 100644 --- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c @@ -1,7 +1,21 @@ /** @file - The common variable operation routines shared by DXE_RINTIME variable + The common variable operation routines shared by DXE_RUNTIME variable module and DXE_SMM variable module. + Caution: This module requires additional review when modified. + This driver will have external input - variable data. They may be input in SMM mode. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API. + They need check input parameter. + + VariableServiceGetVariable() and VariableServiceSetVariable() are external API + to receive datasize and data buffer. The size should be checked carefully. + + VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow, + integer overflow. It should also check attribute to avoid authentication bypass. + Copyright (c) 2009 - 2012, 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 @@ -539,15 +553,13 @@ Reclaim ( EFI_STATUS Status; CHAR16 *VariableNamePtr; CHAR16 *UpdatingVariableNamePtr; + UINTN CommonVariableTotalSize; + UINTN HwErrVariableTotalSize; VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase); - // - // Recalculate the total size of Common/HwErr type variables in non-volatile area. - // - if (!IsVolatile) { - mVariableModuleGlobal->CommonVariableTotalSize = 0; - mVariableModuleGlobal->HwErrVariableTotalSize = 0; - } + + CommonVariableTotalSize = 0; + HwErrVariableTotalSize = 0; // // Start Pointers for the variable. @@ -614,9 +626,9 @@ Reclaim ( CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); CurrPtr += VariableSize; if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + HwErrVariableTotalSize += VariableSize; } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + CommonVariableTotalSize += VariableSize; } } Variable = NextVariable; @@ -630,9 +642,9 @@ Reclaim ( CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize); CurrPtr += VariableSize; if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + HwErrVariableTotalSize += VariableSize; } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + CommonVariableTotalSize += VariableSize; } } @@ -676,9 +688,9 @@ Reclaim ( ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED; CurrPtr += VariableSize; if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + HwErrVariableTotalSize += VariableSize; } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + CommonVariableTotalSize += VariableSize; } } } @@ -706,8 +718,23 @@ Reclaim ( } if (!EFI_ERROR (Status)) { *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer); + if (!IsVolatile) { + mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize; + mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize; + } } else { - *LastVariableOffset = 0; + NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase); + while (IsValidVariableHeader (NextVariable)) { + VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER); + if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize); + } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize); + } + + NextVariable = GetNextVariablePtr (NextVariable); + } + *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase; } FreePool (ValidBuffer); @@ -720,7 +747,8 @@ Reclaim ( @param[in] VariableName Name of the variable to be found @param[in] VendorGuid Vendor GUID to be found. - @param[in] IgnoreRtAttribute Ignore RUNTIME_ACCESS attribute when searching variable. + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute + check at runtime when searching variable. @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information. @retval EFI_SUCCESS Variable found successfully @@ -730,7 +758,7 @@ EFI_STATUS FindVariableEx ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, - IN BOOLEAN IgnoreRtAttribute, + IN BOOLEAN IgnoreRtCheck, IN OUT VARIABLE_POINTER_TRACK *PtrTrack ) { @@ -749,7 +777,7 @@ FindVariableEx ( if (PtrTrack->CurrPtr->State == VAR_ADDED || PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) ) { - if (IgnoreRtAttribute || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { + if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { if (VariableName[0] == 0) { if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { InDeletedVariable = PtrTrack->CurrPtr; @@ -785,9 +813,9 @@ FindVariableEx ( This code finds variable in storage blocks of volatile and non-volatile storage areas. If VariableName is an empty string, then we just return the first qualified variable without comparing VariableName and VendorGuid. - If IgnoreRtAttribute is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS Attribute - when searching existing variable, only VariableName and VendorGuid are compared. - Otherwise, variables with EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime. + If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check + at runtime when searching existing variable, only VariableName and VendorGuid are compared. + Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime. @param[in] VariableName Name of the variable to be found. @param[in] VendorGuid Vendor GUID to be found. @@ -796,7 +824,8 @@ FindVariableEx ( @param[in] Global Pointer to VARIABLE_GLOBAL structure, including base of volatile variable storage area, base of NV variable storage area, and a lock. - @param[in] IgnoreRtAttribute Ignore RUNTIME_ACCESS attribute when searching variable. + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute + check at runtime when searching variable. @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL. @@ -810,7 +839,7 @@ FindVariable ( IN EFI_GUID *VendorGuid, OUT VARIABLE_POINTER_TRACK *PtrTrack, IN VARIABLE_GLOBAL *Global, - IN BOOLEAN IgnoreRtAttribute + IN BOOLEAN IgnoreRtCheck ) { EFI_STATUS Status; @@ -842,7 +871,7 @@ FindVariable ( PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]); PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile); - Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtAttribute, PtrTrack); + Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack); if (!EFI_ERROR (Status)) { return Status; } @@ -1882,10 +1911,98 @@ Done: return Status; } +/** + Check if a Unicode character is a hexadecimal character. + + This function checks if a Unicode character is a + hexadecimal character. The valid hexadecimal character is + L'0' to L'9', L'a' to L'f', or L'A' to L'F'. + + + @param Char The character to check against. + + @retval TRUE If the Char is a hexadecmial character. + @retval FALSE If the Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +IsHexaDecimalDigitCharacter ( + IN CHAR16 Char + ) +{ + return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f')); +} + +/** + + This code checks if variable is hardware error record variable or not. + + According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid + and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value. + + @param VariableName Pointer to variable name. + @param VendorGuid Variable Vendor Guid. + + @retval TRUE Variable is hardware error record variable. + @retval FALSE Variable is not hardware error record variable. + +**/ +BOOLEAN +EFIAPI +IsHwErrRecVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) || + (StrLen (VariableName) != StrLen (L"HwErrRec####")) || + (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) || + !IsHexaDecimalDigitCharacter (VariableName[0x8]) || + !IsHexaDecimalDigitCharacter (VariableName[0x9]) || + !IsHexaDecimalDigitCharacter (VariableName[0xA]) || + !IsHexaDecimalDigitCharacter (VariableName[0xB])) { + return FALSE; + } + + return TRUE; +} + +/** + This code checks if variable should be treated as read-only variable. + + @param[in] VariableName Name of the Variable. + @param[in] VendorGuid GUID of the Variable. + + @retval TRUE This variable is read-only variable. + @retval FALSE This variable is NOT read-only variable. + +**/ +BOOLEAN +IsReadOnlyVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { + if ((StrCmp (VariableName, EFI_SETUP_MODE_NAME) == 0) || + (StrCmp (VariableName, EFI_SIGNATURE_SUPPORT_NAME) == 0) || + (StrCmp (VariableName, EFI_SECURE_BOOT_MODE_NAME) == 0)) { + return TRUE; + } + } + + return FALSE; +} + /** This code finds variable in storage blocks (Volatile or Non-Volatile). + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize is external input. + This function will do basic validation, before parse the data. + @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @param Attributes Attribute value of the variable found. @@ -1963,6 +2080,9 @@ Done: This code Finds the Next available variable. + 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 VariableName Pointer to variable name. @param VendorGuid Variable Vendor Guid. @@ -2108,6 +2228,13 @@ Done: This code sets variable in storage blocks (Volatile or Non-Volatile). + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @param Attributes Attribute value of the variable found @@ -2145,6 +2272,10 @@ VariableServiceSetVariable ( return EFI_INVALID_PARAMETER; } + if (IsReadOnlyVariable (VariableName, VendorGuid)) { + return EFI_WRITE_PROTECTED; + } + if (DataSize != 0 && Data == NULL) { return EFI_INVALID_PARAMETER; } @@ -2197,10 +2328,7 @@ VariableServiceSetVariable ( (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) { return EFI_INVALID_PARAMETER; } - // - // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX". - // - if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) { + if (!IsHwErrRecVariable(VariableName, VendorGuid)) { return EFI_INVALID_PARAMETER; } } else { @@ -2214,6 +2342,16 @@ VariableServiceSetVariable ( } } + if (AtRuntime ()) { + // + // HwErrRecSupport Global Variable identifies the level of hardware error record persistence + // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS. + // + if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) { + return EFI_WRITE_PROTECTED; + } + } + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); // @@ -2255,7 +2393,10 @@ VariableServiceSetVariable ( Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE); } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) { - Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes); + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE); + if (EFI_ERROR (Status)) { + Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes); + } } else { Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes); } @@ -2270,6 +2411,9 @@ VariableServiceSetVariable ( This code returns information about the EFI variables. + 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 Attributes Attributes bitmask to specify the type of variables on which to return information. @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available @@ -2431,6 +2575,9 @@ VariableServiceQueryVariableInfo ( /** This function reclaims variable storage if free size is below the threshold. + Caution: This function may be invoked at SMM mode. + Care must be taken to make sure not security issue. + **/ VOID ReclaimForOS(