/** @file Library implementing the LockBox interface for OVMF Copyright (C) 2013, Red Hat, Inc. Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #pragma pack(1) typedef struct { EFI_GUID Guid; EFI_PHYSICAL_ADDRESS OrigAddress; EFI_PHYSICAL_ADDRESS CopyAddress; UINT32 Size; UINT64 Attributes; } LOCK_BOX_ENTRY; #pragma pack() LOCK_BOX_GLOBAL *mLockBoxGlobal = NULL; STATIC LOCK_BOX_ENTRY *StartOfEntries = NULL; STATIC LOCK_BOX_ENTRY *EndOfEntries = NULL; RETURN_STATUS EFIAPI LockBoxLibInitialize ( VOID ) { UINTN NumEntries; ASSERT (!FeaturePcdGet (PcdSmmSmramRequire)); if (PcdGet32 (PcdOvmfLockBoxStorageSize) < sizeof (LOCK_BOX_GLOBAL)) { return RETURN_UNSUPPORTED; } mLockBoxGlobal = (LOCK_BOX_GLOBAL *)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase); StartOfEntries = ((LOCK_BOX_ENTRY *)(mLockBoxGlobal + 1)); NumEntries = ((PcdGet32 (PcdOvmfLockBoxStorageSize) - sizeof (LOCK_BOX_GLOBAL)) / sizeof (LOCK_BOX_ENTRY)); EndOfEntries = StartOfEntries + NumEntries; if (mLockBoxGlobal->Signature != LOCK_BOX_GLOBAL_SIGNATURE) { // // Note: This code depends on the lock box being cleared in early // PEI before usage, so the SubPageBuffer and SubPageRemaining // fields don't need to be set to 0. // mLockBoxGlobal->Signature = LOCK_BOX_GLOBAL_SIGNATURE; } return RETURN_SUCCESS; } /** Find LockBox entry based on GUID. @param[in] Guid The GUID to search for. @return Address of the LOCK_BOX_ENTRY found. If NULL, then the item was not found, and there is no space left to store a new item. If non-NULL and LOCK_BOX_ENTRY.Size == 0, then the item was not found, but a new item can be inserted at the returned location. If non-NULL and LOCK_BOX_ENTRY.Size > 0, then the item was found. **/ STATIC LOCK_BOX_ENTRY * EFIAPI FindHeaderByGuid ( IN CONST EFI_GUID *Guid ) { LOCK_BOX_ENTRY *Header; for (Header = StartOfEntries; Header < EndOfEntries; Header++) { if ((Header->Size == 0) || CompareGuid (Guid, &Header->Guid)) { return Header; } } return NULL; } /** This function will save confidential information to lockbox. @param Guid the guid to identify the confidential information @param Buffer the address of the confidential information @param Length the length of the confidential information @retval RETURN_SUCCESS the information is saved successfully. @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0 @retval RETURN_ALREADY_STARTED the requested GUID already exist. @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information. @retval RETURN_ACCESS_DENIED it is too late to invoke this interface @retval RETURN_NOT_STARTED it is too early to invoke this interface @retval RETURN_UNSUPPORTED the service is not supported by implementaion. **/ RETURN_STATUS EFIAPI SaveLockBox ( IN GUID *Guid, IN VOID *Buffer, IN UINTN Length ) { LOCK_BOX_ENTRY *Header; VOID *CopyBuffer; DEBUG (( DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p Length=0x%x\n", __func__, Guid, Buffer, (UINT32)Length )); if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) { return RETURN_INVALID_PARAMETER; } if (Length > 0xFFFFFFFF) { return RETURN_OUT_OF_RESOURCES; } Header = FindHeaderByGuid (Guid); if (Header == NULL) { return RETURN_OUT_OF_RESOURCES; } if (Header->Size > 0) { return RETURN_ALREADY_STARTED; } CopyBuffer = AllocateAcpiNvsPool (Length); if (CopyBuffer == NULL) { return RETURN_OUT_OF_RESOURCES; } // // overwrite the current terminator header with new metadata // CopyGuid (&Header->Guid, Guid); Header->OrigAddress = (UINTN)Buffer; Header->CopyAddress = (UINTN)CopyBuffer; Header->Size = (UINT32)Length; Header->Attributes = 0; // // copy contents // CopyMem (CopyBuffer, Buffer, Length); return RETURN_SUCCESS; } /** This function will set lockbox attributes. @param Guid the guid to identify the confidential information @param Attributes the attributes of the lockbox @retval RETURN_SUCCESS the information is saved successfully. @retval RETURN_INVALID_PARAMETER attributes is invalid. @retval RETURN_NOT_FOUND the requested GUID not found. @retval RETURN_ACCESS_DENIED it is too late to invoke this interface @retval RETURN_NOT_STARTED it is too early to invoke this interface @retval RETURN_UNSUPPORTED the service is not supported by implementaion. **/ RETURN_STATUS EFIAPI SetLockBoxAttributes ( IN GUID *Guid, IN UINT64 Attributes ) { LOCK_BOX_ENTRY *Header; DEBUG (( DEBUG_VERBOSE, "%a: Guid=%g Attributes=0x%Lx\n", __func__, Guid, Attributes )); if (Guid == NULL) { return RETURN_INVALID_PARAMETER; } Header = FindHeaderByGuid (Guid); if (!Header || (Header->Size == 0)) { return RETURN_NOT_FOUND; } Header->Attributes = Attributes; return RETURN_SUCCESS; } /** This function will update confidential information to lockbox. @param Guid the guid to identify the original confidential information @param Offset the offset of the original confidential information @param Buffer the address of the updated confidential information @param Length the length of the updated confidential information @retval RETURN_SUCCESS the information is saved successfully. @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0. @retval RETURN_NOT_FOUND the requested GUID not found. @retval RETURN_BUFFER_TOO_SMALL for lockbox without attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY, the original buffer to too small to hold new information. @retval RETURN_OUT_OF_RESOURCES for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY, no enough resource to save the information. @retval RETURN_ACCESS_DENIED it is too late to invoke this interface @retval RETURN_NOT_STARTED it is too early to invoke this interface @retval RETURN_UNSUPPORTED the service is not supported by implementaion. **/ RETURN_STATUS EFIAPI UpdateLockBox ( IN GUID *Guid, IN UINTN Offset, IN VOID *Buffer, IN UINTN Length ) { LOCK_BOX_ENTRY *Header; DEBUG (( DEBUG_VERBOSE, "%a: Guid=%g Offset=0x%x Length=0x%x\n", __func__, Guid, (UINT32)Offset, (UINT32)Length )); if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) { return RETURN_INVALID_PARAMETER; } Header = FindHeaderByGuid (Guid); if (!Header || (Header->Size == 0)) { return RETURN_NOT_FOUND; } if ((Header->Size < Offset) || (Length > Header->Size - Offset)) { return RETURN_BUFFER_TOO_SMALL; } CopyMem ((UINT8 *)(UINTN)(Header->CopyAddress) + Offset, Buffer, Length); return RETURN_SUCCESS; } /** This function will restore confidential information from lockbox. @param Guid the guid to identify the confidential information @param Buffer the address of the restored confidential information NULL means restored to original address, Length MUST be NULL at same time. @param Length the length of the restored confidential information @retval RETURN_SUCCESS the information is restored successfully. @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL. @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute. @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information. @retval RETURN_NOT_FOUND the requested GUID not found. @retval RETURN_NOT_STARTED it is too early to invoke this interface @retval RETURN_ACCESS_DENIED not allow to restore to the address @retval RETURN_UNSUPPORTED the service is not supported by implementaion. **/ RETURN_STATUS EFIAPI RestoreLockBox ( IN GUID *Guid, IN VOID *Buffer OPTIONAL, IN OUT UINTN *Length OPTIONAL ) { LOCK_BOX_ENTRY *Header; DEBUG (( DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __func__, Guid, Buffer )); if ((Guid == NULL) || ((Buffer == NULL) && (Length != NULL)) || ((Buffer != NULL) && (Length == NULL))) { return EFI_INVALID_PARAMETER; } Header = FindHeaderByGuid (Guid); if (!Header || (Header->Size == 0)) { return RETURN_NOT_FOUND; } if (Buffer == NULL) { if (!(Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE)) { return RETURN_WRITE_PROTECTED; } if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) { return RETURN_UNSUPPORTED; } Buffer = (VOID *)(UINTN)Header->OrigAddress; } // // Set RestoreLength // if (Length != NULL) { if (Header->Size > *Length) { // // Input buffer is too small to hold all data. // *Length = Header->Size; return EFI_BUFFER_TOO_SMALL; } *Length = Header->Size; } CopyMem (Buffer, (VOID *)(UINTN)Header->CopyAddress, Header->Size); return RETURN_SUCCESS; } /** This function will restore confidential information from all lockbox which have RestoreInPlace attribute. @retval RETURN_SUCCESS the information is restored successfully. @retval RETURN_NOT_STARTED it is too early to invoke this interface @retval RETURN_UNSUPPORTED the service is not supported by implementaion. **/ RETURN_STATUS EFIAPI RestoreAllLockBoxInPlace ( VOID ) { LOCK_BOX_ENTRY *Header; for (Header = StartOfEntries; Header < EndOfEntries && Header->Size > 0; Header++) { if (Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) { VOID *Buffer; if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) { return RETURN_UNSUPPORTED; } Buffer = (VOID *)(UINTN)Header->OrigAddress; CopyMem (Buffer, (VOID *)(UINTN)Header->CopyAddress, Header->Size); DEBUG (( DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __func__, &Header->Guid, Buffer )); } } return RETURN_SUCCESS; }