/** @file Provide support functions for insyde secure variable. ;****************************************************************************** ;* Copyright (c) 2012 - 2018, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include "InsydeSecureVariable.h" #include "AuthService.h" #include "VarDefault.h" #include EFI_BDS_ENTRY mOriginalBdsEntry; /** Check the input Insyde variable password size is correct. @param[in] Data Pointer to a buffer of the variable contents. @param[in] DataSize Size of Data buffer. @retval TRUE The password size is correct. @retval FALSE The password size is incorrect. **/ STATIC BOOLEAN IsPasswordSizeCorrect ( IN CONST UINT8 *Data, IN UINTN DataSize ) { UINT8 PasswordLen; if (Data == NULL) { return FALSE; } PasswordLen = *(Data + INSYDE_VARIABLE_PASSWORD_HEADER_SIZE); if (INSYDE_VARIABLE_PASSWORD_HEADER_SIZE + sizeof (UINT8) + PasswordLen + sizeof (UINT8) != DataSize) { return FALSE; } return TRUE; } /** Check Insyde password state is locked or unlocked. @retval TRUE Insyde password is in locked state. @retval FALSE Insyde password is in unlocked state. **/ STATIC BOOLEAN IsInsydePasswordLocked ( VOID ) { if (mSmst == NULL) { return mVariableModuleGlobal->InsydeSecureVariableLocked; } else { return mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->InsydeSecureVariableLocked; } } /** Change the Insyde password state to unlocked state. @retval EFI_SUCCESS Change Insyde variable state to unlocked state. @retval EFI_ALREADY_STARTED The password state is already in unlocked state. **/ STATIC EFI_STATUS UnlockInsydePassword ( VOID ) { if (!IsInsydePasswordLocked ()) { return EFI_ALREADY_STARTED; } if (mSmst == NULL) { mVariableModuleGlobal->InsydeSecureVariableLocked = FALSE; } else { mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->InsydeSecureVariableLocked = FALSE; } return EFI_SUCCESS; } /** Change the Insyde password state to locked state. @retval EFI_SUCCESS Change Insyde variable state to locked state. @retval EFI_ALREADY_STARTED The password state is already in locked state. **/ STATIC EFI_STATUS LockInsydePassword ( VOID ) { if (IsInsydePasswordLocked ()) { return EFI_ALREADY_STARTED; } if (mSmst == NULL) { mVariableModuleGlobal->InsydeSecureVariableLocked = TRUE; } else { mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->InsydeSecureVariableLocked = TRUE; } return EFI_SUCCESS; } /** This function uses input data to calculate encrypted hash data. User need allocate buffer for EncryptedHashData buffer before invoking this function. @param[in] Data Pointer to input original data buffer. @param[out] EncryptedHashData Pointer to output encrypted hash data buffer. @retval EFI_SUCCESS The hash data is same as the content of AdminPassword. @retval EFI_UNSUPPORTED System doesn't support hash protocol. @retval EFI_INVALID_PARAMETER Data or EncryptedHashData is NULL. **/ STATIC EFI_STATUS GetEncryptedHashData ( IN VOID *Data, OUT VOID *EncryptedHashData ) { EFI_STATUS Status; EFI_HASH_OUTPUT Digest; UINTN PasswordLen; UINT8 *WorkingData; CHAR8 CombinedData[CERT_DATA_SIZE]; if (Data == NULL || EncryptedHashData == NULL) { return EFI_INVALID_PARAMETER; } if (mHash == NULL) { return EFI_UNSUPPORTED; } WorkingData = (UINT8 *) Data; PasswordLen = (UINTN) *WorkingData; ZeroMem (CombinedData, CERT_DATA_SIZE); GetCombinedData (WorkingData, PasswordLen + 1, CombinedData); Digest.Sha256Hash = (EFI_SHA256_HASH *) EncryptedHashData; if (PasswordLen + 1 > CERT_DATA_SIZE) { Status = mHash->Hash ( mHash, &gEfiHashAlgorithmSha256Guid, FALSE, (UINT8 *)CombinedData, CERT_DATA_SIZE, (EFI_HASH_OUTPUT *) &Digest ); if (EFI_ERROR (Status)) { return Status; } Status = mHash->Hash ( mHash, &gEfiHashAlgorithmSha256Guid, TRUE, &WorkingData[CERT_DATA_SIZE], PasswordLen + 1 - CERT_DATA_SIZE, (EFI_HASH_OUTPUT *) &Digest ); } else { Status = mHash->Hash ( mHash, &gEfiHashAlgorithmSha256Guid, FALSE, (UINT8 *)CombinedData, CERT_DATA_SIZE, (EFI_HASH_OUTPUT *) &Digest ); } return Status; } /** This function uses to hash input data to compare with hash data which saved in AdminPassword variable. If AdminPassword doesn't exit, return EFI_SUCCESS directly. @param[in] Data Pointer to data buffer. @retval EFI_SUCCESS The hash data is same as the content of AdminPassword. @retval EFI_UNSUPPORTED System doesn't support hash protocol. @retval EFI_SECURITY_VIOLATION The hash data isn't same as the content of AdminPassword. **/ STATIC EFI_STATUS CheckWithAdminPassword ( IN VOID *Data ) { EFI_STATUS Status; UINTN VariableCount; VARIABLE_GLOBAL *Global; VARIABLE_POINTER_TRACK Variable; VariableCount = 0; Global = &mVariableModuleGlobal->VariableBase; Status = FindVariableByLifetimeInAllRegions (EFI_ADMIN_PASSWORD_NAME, &gInsydeSecureFirmwarePasswordGuid, &Variable, &VariableCount, Global); if (Variable.CurrPtr == NULL) { Status = EFI_SUCCESS; } else { Status = GetEncryptedHashData (Data, mSha256Hash); if (!EFI_ERROR (Status)) { if (CompareMem (GetVariableDataPtr (Variable.CurrPtr), mSha256Hash, SHA256_DIGEST_SIZE) != 0) { Status = EFI_SECURITY_VIOLATION; } } } return Status; } /** This function uses to execute unlock admin password process. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval EFI_SUCCESS System changes admin password state to unlocked successful. @retval EFI_INVALID_PARAMETER Any input parameter is NULL. @retval EFI_UNSUPPORTED The input data isn't a valid unlock admin password variable. **/ STATIC EFI_STATUS ExecuteUnlockPasswordProcess ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { EFI_STATUS Status; EFI_VARIABLE_AUTHENTICATION *CertData; if (VariableName == NULL || VendorGuid == NULL || Data == NULL) { return EFI_INVALID_PARAMETER; } if (!IsUnlockPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return EFI_UNSUPPORTED; } CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; Status = CheckWithAdminPassword ((VOID *) &CertData->AuthInfo.CertData); if (!EFI_ERROR (Status)) { Status = UnlockInsydePassword (); } return Status; } /** This function uses to update the contents of admin password. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Data Pointer to a buffer of the variable contents. @param[in] DataSize Size of Data buffer. @param[in] Variable The variable information which is used to keep track of variable usage. @param[in] Attributes Attribute value of the variable found. @param[in] Global Pointer to VARIABLE_GLOBAL instance. @retval EFI_SUCCESS System updates admin password successful. @retval EFI_INVALID_PARAMETER Any input parameter is NULL. @retval EFI_UNSUPPORTED The input data isn't a valid admin password variable. **/ STATIC EFI_STATUS UpdateAdminPassword ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN CONST VOID *Data, IN UINTN DataSize, IN VARIABLE_POINTER_TRACK *Variable, IN UINT32 Attributes, IN VARIABLE_GLOBAL *Global ) { EFI_VARIABLE_AUTHENTICATION *CertData; EFI_STATUS Status; EFI_TIME TimeStamp; UINTN UpdateDatasize; if (VariableName == NULL || VendorGuid == NULL || Data == NULL || Variable == NULL || Global == NULL) { return EFI_INVALID_PARAMETER; } if (!IsValidAdminPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return EFI_UNSUPPORTED; } CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; Status = GetEncryptedHashData (&CertData->AuthInfo.CertData, mSha256Hash); if (EFI_ERROR (Status)) { return Status; } UpdateDatasize = SHA256_DIGEST_SIZE; if (IsDeleteAdminPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { // // Set DataSize to 0 to delete original variable. // UpdateDatasize = 0; } // // Set all of byte to 0xFF in EFI_TIME in variable header to indicate this is a insyde secure variable. // SetMem (&TimeStamp, sizeof (EFI_TIME), 0xFF); Status = UpdateVariable ( VariableName, VendorGuid, (VOID *) mSha256Hash, UpdateDatasize, Attributes, 0, 0, Variable, &TimeStamp, Global ); return Status; } /** This function uses to update normal Insyde secure variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Data Pointer to a buffer of the variable contents. @param[in] DataSize Size of Data buffer. @param[in] Variable The variable information which is used to keep track of variable usage. @param[in] Attributes Attribute value of the variable found. @param[in] Global Pointer to VARIABLE_GLOBAL instance. @retval EFI_SUCCESS System updates normal Insyde secure variable successful. @retval EFI_INVALID_PARAMETER Any input parameter is NULL. @retval EFI_UNSUPPORTED The input contents isn't a valid normal Insyde secure variable. **/ STATIC EFI_STATUS UpdateNormalInsydeVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN CONST VOID *Data, IN UINTN DataSize, IN VARIABLE_POINTER_TRACK *Variable, IN UINT32 Attributes, IN VARIABLE_GLOBAL *Global ) { EFI_TIME TimeStamp; UINTN UpdateDatasize; UINT8 *UpdateData; EFI_STATUS Status; if (VariableName == NULL || VendorGuid == NULL || Data == NULL || Variable == NULL || Global == NULL) { return EFI_INVALID_PARAMETER; } if (!IsNormalInsydeSecureVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return EFI_UNSUPPORTED; } UpdateDatasize = DataSize - INSYDE_VARIABLE_HEADER_SIZE; UpdateData = (UINT8 *) Data; UpdateData += INSYDE_VARIABLE_HEADER_SIZE; // // Set all of byte to 0xFF in EFI_TIME in variable header to indicate this is a insyde secure variable. // SetMem (&TimeStamp, sizeof (EFI_TIME), 0xFF); Status = UpdateVariable ( VariableName, VendorGuid, UpdateData, UpdateDatasize, Attributes, 0, 0, Variable, &TimeStamp, Global ); return Status; } /** This function uses to check the variable is whether a valid Insyde secure variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE System updates normal Insyde secure variable successful. @retval FALSE Any input parameter is NULL. **/ BOOLEAN IsValidInsydeSecureVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { if (IsValidCheckAdminPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data) || IsValidAdminPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data) || IsNormalInsydeSecureVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return TRUE; } return FALSE; } /** This function uses to check the variable is whether a valid check admin password variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is a valid check admin password variable. @retval FALSE This isn't a valid check admin password variable. **/ BOOLEAN IsValidCheckAdminPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { if (IsUnlockPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data) || IsLockPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return TRUE; } return FALSE; } /** This function uses to check the variable is whether an unlock check admin password variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is an unlock check admin password variable. @retval FALSE This isn't an unlock check admin password variable. **/ BOOLEAN IsUnlockPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { UINT8 *Action; if (VariableName == NULL || VendorGuid == NULL || Data == NULL) { return FALSE; } if (!IsCheckAdminPasswordVariable (VariableName, VendorGuid)) { return FALSE; } if (IsPasswordSizeCorrect (Data, DataSize)) { Action = (UINT8 *) Data; Action += (DataSize - sizeof (UINT8)); if (IsInsydeSecureVariable (Attributes, DataSize, Data) && *Action == UNLOCK_SECURE_VARIABLE) { return TRUE; } } return FALSE; } /** This function uses to check the variable is whether a lock check admin password variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is a lock check admin password variable. @retval FALSE This isn't a lock check admin password variable. **/ BOOLEAN IsLockPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { UINT8 *Action; if (VariableName == NULL || VendorGuid == NULL || Data == NULL) { return FALSE; } if (!IsCheckAdminPasswordVariable (VariableName, VendorGuid)) { return FALSE; } if (DataSize == LOCK_PASSWORD_VARIABLE_SIZE) { Action = (UINT8 *) Data; Action += (LOCK_PASSWORD_VARIABLE_SIZE - sizeof (UINT8)); if (IsInsydeSecureVariable (Attributes, DataSize, Data) && *Action == LOCK_SECURE_VARIABLE) { return TRUE; } } return FALSE; } /** According to variable name and variable to check this variable is whether a CheckAdminPassword variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is a CheckAdminPassword variable. @retval FALSE This isn't a CheckAdminPassword variable. **/ BOOLEAN IsCheckAdminPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_CHECK_ADMIN_PASSWORD_NAME) == 0 && CompareGuid (VendorGuid, &gInsydeSecureFirmwarePasswordGuid)) { return TRUE; } } return FALSE; } /** Check the data contents and attributes to determine this is whether a insyde secure variable. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is a AdminPassword variable. @retval FALSE This isn't a AdminPassword variable. **/ BOOLEAN IsInsydeSecureVariable ( IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS && IsInsydeSecureType (DataSize, Data)) { return TRUE; } return FALSE; } /** Using the data contents to check this is whether a Insyde secure type. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is Insyde secure type. @retval FALSE This isn't Insyde secure type. **/ BOOLEAN IsInsydeSecureType ( IN UINTN DataSize, IN CONST VOID *Data ) { EFI_VARIABLE_AUTHENTICATION *CertData; if (Data == NULL) { return FALSE; } if (DataSize >= INSYDE_VARIABLE_PASSWORD_HEADER_SIZE + sizeof (UINT8)) { CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; if (CertData->AuthInfo.Hdr.wCertificateType == WIN_CERT_TYPE_EFI_GUID && CompareGuid (&CertData->AuthInfo.CertType, &gIbvCertTypeInsydeSecureGuid)) { return TRUE; } } return FALSE; } /** This function uses to check the variable is whether a valid admin password variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is a valid admin password variable. @retval FALSE This isn't a valid admin password variable. **/ BOOLEAN IsValidAdminPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { if (IsDeleteAdminPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data) || IsReplaceAdminPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return TRUE; } return FALSE; } /** This function uses to check the variable is whether a delete admin password variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is a delete admin password variable. @retval FALSE This isn't a delete admin password variable. **/ BOOLEAN IsDeleteAdminPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { if (VariableName == NULL || VendorGuid == NULL || Data == NULL) { return FALSE; } if (!IsAdminPasswordVariable (VariableName, VendorGuid)) { return FALSE; } if (IsInsydeSecureVariable (Attributes, DataSize, Data) && DataSize == DELETE_PASSWORD_VARIABLE_SIZE) { return TRUE; } return FALSE; } /** This function uses to check the variable is whether a replace admin password variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is a replace admin password variable. @retval FALSE This isn't a replace admin password variable. **/ BOOLEAN IsReplaceAdminPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { UINT8 *WorkingPtr; if (VariableName == NULL || VendorGuid == NULL || Data == NULL) { return FALSE; } if (!IsAdminPasswordVariable (VariableName, VendorGuid)) { return FALSE; } WorkingPtr = (UINT8 *) Data; if (IsInsydeSecureVariable (Attributes, DataSize, Data) && IsPasswordSizeCorrect (Data, DataSize) && WorkingPtr[DataSize - 1] == REPLACE_ADMIN_PASSWORD) { return TRUE; } return FALSE; } /** According to variable name and variable to check this variable is whether a AdminPassword variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is a AdminPassword variable. @retval FALSE This isn't a AdminPassword variable. **/ BOOLEAN IsAdminPasswordVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_ADMIN_PASSWORD_NAME) == 0 && CompareGuid (VendorGuid, &gInsydeSecureFirmwarePasswordGuid)) { return TRUE; } } return FALSE; } /** This function uses to check the variable is whether a valid admin password variable. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable found. @param[in] DataSize Size of Data buffer. @param[in] Data Pointer to a buffer of the variable contents. @retval TRUE This is a valid admin password variable. @retval FALSE This isn't a valid admin password variable. **/ BOOLEAN IsNormalInsydeSecureVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN CONST VOID *Data ) { if (VariableName == NULL || VendorGuid == NULL || Data == NULL) { return FALSE; } if (IsInsydeSecureVariable (Attributes, DataSize, Data) && !IsCheckAdminPasswordVariable (VariableName, VendorGuid) && !IsAdminPasswordVariable (VariableName, VendorGuid)) { return TRUE; } return FALSE; } /** This function uses to process Insyde secure variables. @param[in] VariableName A CHAR16 string of variable name. @param[in] VendorGuid Variable vendor GUID. @param[in] Data Pointer to a buffer of the variable contents. @param[in] DataSize Size of Data buffer. @param[in] Variable The variable information which is used to keep track of variable usage. @param[in] Attributes Attribute value of the variable found. @param[in] Global Pointer to VARIABLE_GLOBAL instance. @retval EFI_SUCCESS Change Insyde variable state to unlocked state. @retval EFI_INVALID_PARAMETER Any input parameter is NULL. @retval EFI_WRITE_PROTECTED Udpate any insyde secure variable except for Unlock password state when the insyde secure variable state is locked. **/ EFI_STATUS ProcessInsydeSecureVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN CONST VOID *Data, IN UINTN DataSize, IN VARIABLE_POINTER_TRACK *Variable, IN UINT32 Attributes, IN VARIABLE_GLOBAL *Global ) { EFI_STATUS Status; if (VariableName == NULL || VendorGuid == NULL || Data == NULL || Variable == NULL || Global == NULL) { return EFI_INVALID_PARAMETER; } // // TODO: // Normal functionality for Insyde Secure variable has been tested. // But we don't do sufficient for Insyde secure variable test if Insyde secure variable is // Stored in variable default store. Need do this once customer need use this feature. // if (Variable->CurrPtr != NULL && !IsExistingInsydeSecureVariable (Variable)) { // // If caller attempts to change attributes from Insyde secure variable to other attributes, just return // EFI_WRITE_PROTECTED directly. // return EFI_WRITE_PROTECTED; } if (!IsValidInsydeSecureVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return EFI_UNSUPPORTED; } if (IsInsydePasswordLocked () && !IsUnlockPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { return EFI_WRITE_PROTECTED; } if (IsUnlockPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { Status = ExecuteUnlockPasswordProcess (VariableName, VendorGuid, Attributes, DataSize, Data); } else if (IsLockPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { Status = LockInsydePassword (); } else if (IsValidAdminPasswordVariable (VariableName, VendorGuid, Attributes, DataSize, Data)) { Status = UpdateAdminPassword (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, Global); } else { Status = UpdateNormalInsydeVariable (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, Global); } return Status; } /** This function uses VARIABLE_POINTER_TRACK to check this variable is whether an existing insyde secure variable. @param[in] Variable The variable information which is used to keep track of variable usage. @retval TRUE The variable is an existing Insyde secure variable. @retval FALSE The variable isn't an existing Insyde secure variable. **/ BOOLEAN IsExistingInsydeSecureVariable ( IN CONST VARIABLE_POINTER_TRACK *Variable ) { EFI_TIME TimeStamp; if (Variable == NULL || Variable->CurrPtr == NULL) { return FALSE; } // // If define Insyde secure variable in variable default store, return TRUE directly. // if (AddressInVariableDefaultRegion ((EFI_PHYSICAL_ADDRESS) (UINTN) Variable->CurrPtr) && (Variable->CurrPtr->Attributes & EFI_VARIABLE_INSYDE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_INSYDE_AUTHENTICATED_WRITE_ACCESS) { return TRUE; } SetMem (&TimeStamp, sizeof (EFI_TIME), 0xFF); if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0 || CompareMem (&TimeStamp, &Variable->CurrPtr->TimeStamp, sizeof (EFI_TIME)) != 0) { return FALSE; } return TRUE; } /** BdsEntry hook function. This function uses to set Insyde variable state to locked and then enter original BdsEntry (). @param[in] This The EFI_BDS_ARCH_PROTOCOL instance. **/ STATIC VOID EFIAPI BdsEntry ( IN EFI_BDS_ARCH_PROTOCOL *This ) { mVariableModuleGlobal->InsydeSecureVariableLocked = TRUE; mOriginalBdsEntry (This); } /** This function uses to hook original BdsEntry (). @param[in] Event Event whose notification function is being invoked. @param[in] Event Pointer to the notification function's context. **/ STATIC VOID EFIAPI BdsCallback ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; EFI_BDS_ARCH_PROTOCOL *Bds; Status = gBS->LocateProtocol ( &gEfiBdsArchProtocolGuid, NULL, (VOID **) &Bds ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return; } mOriginalBdsEntry = Bds->Entry; Bds->Entry = BdsEntry; return; } /** Initializes variable store area for non-volatile and volatile variable. @retval EFI_SUCCESS Hook BdsEntry () successful or register callback () successful. @retval EFI_OUT_OF_RESOURCES Register callback() for gEfiBdsArchProtocolGuid failed. **/ EFI_STATUS InitializeInsydeVariableLockedState ( VOID ) { EFI_STATUS Status; EFI_BDS_ARCH_PROTOCOL *Bds; EFI_EVENT Event; VOID *Registration; Status = gBS->LocateProtocol ( &gEfiBdsArchProtocolGuid, NULL, (VOID **) &Bds ); if (!EFI_ERROR (Status)) { mOriginalBdsEntry = Bds->Entry; Bds->Entry = BdsEntry; } else { Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, BdsCallback, NULL, &Event ); ASSERT_EFI_ERROR (Status); // // Register for protocol notifications on this event // Status = gBS->RegisterProtocolNotify ( &gEfiBdsArchProtocolGuid, Event, &Registration ); ASSERT_EFI_ERROR (Status); } return Status; }