Home | History | Annotate | Download | only in LockBoxLib
      1 /** @file
      2 
      3   Library implementing the LockBox interface for OVMF
      4 
      5   Copyright (C) 2013, Red Hat, Inc.
      6   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
      7 
      8   This program and the accompanying materials are licensed and made available
      9   under the terms and conditions of the BSD License which accompanies this
     10   distribution. The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php
     12 
     13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     14   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include <Uefi.h>
     19 #include <Library/BaseMemoryLib.h>
     20 #include <Library/DebugLib.h>
     21 #include <Library/LockBoxLib.h>
     22 #include <Library/PcdLib.h>
     23 #include <LockBoxLib.h>
     24 
     25 #pragma pack(1)
     26 typedef struct {
     27   EFI_GUID             Guid;
     28   EFI_PHYSICAL_ADDRESS OrigAddress;
     29   EFI_PHYSICAL_ADDRESS CopyAddress;
     30   UINT32               Size;
     31   UINT64               Attributes;
     32 } LOCK_BOX_ENTRY;
     33 #pragma pack()
     34 
     35 LOCK_BOX_GLOBAL *mLockBoxGlobal = NULL;
     36 STATIC LOCK_BOX_ENTRY *StartOfEntries = NULL;
     37 STATIC LOCK_BOX_ENTRY *EndOfEntries = NULL;
     38 
     39 RETURN_STATUS
     40 EFIAPI
     41 LockBoxLibInitialize (
     42   VOID
     43   )
     44 {
     45   UINTN NumEntries;
     46 
     47   ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
     48 
     49   if (PcdGet32 (PcdOvmfLockBoxStorageSize) < sizeof (LOCK_BOX_GLOBAL)) {
     50     return RETURN_UNSUPPORTED;
     51   }
     52 
     53   mLockBoxGlobal = (LOCK_BOX_GLOBAL *)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase);
     54   StartOfEntries = ((LOCK_BOX_ENTRY *) (mLockBoxGlobal + 1));
     55   NumEntries = ((PcdGet32 (PcdOvmfLockBoxStorageSize) - sizeof (LOCK_BOX_GLOBAL)) /
     56                 sizeof (LOCK_BOX_ENTRY));
     57   EndOfEntries = StartOfEntries + NumEntries;
     58   if (mLockBoxGlobal->Signature != LOCK_BOX_GLOBAL_SIGNATURE) {
     59     //
     60     // Note: This code depends on the lock box being cleared in early
     61     // PEI before usage, so the SubPageBuffer and SubPageRemaining
     62     // fields don't need to be set to 0.
     63     //
     64     mLockBoxGlobal->Signature = LOCK_BOX_GLOBAL_SIGNATURE;
     65   }
     66   return RETURN_SUCCESS;
     67 }
     68 
     69 
     70 /**
     71   Find LockBox entry based on GUID.
     72 
     73   @param[in] Guid  The GUID to search for.
     74 
     75   @return  Address of the LOCK_BOX_ENTRY found.
     76 
     77            If NULL, then the item was not found, and there is no space
     78            left to store a new item.
     79 
     80            If non-NULL and LOCK_BOX_ENTRY.Size == 0, then the item was not
     81            found, but a new item can be inserted at the returned location.
     82 
     83            If non-NULL and LOCK_BOX_ENTRY.Size > 0, then the item was found.
     84 **/
     85 STATIC
     86 LOCK_BOX_ENTRY *
     87 EFIAPI
     88 FindHeaderByGuid (
     89   IN CONST EFI_GUID *Guid
     90   )
     91 {
     92   LOCK_BOX_ENTRY *Header;
     93 
     94   for (Header = StartOfEntries; Header < EndOfEntries; Header++) {
     95     if (Header->Size == 0 || CompareGuid (Guid, &Header->Guid)) {
     96       return Header;
     97     }
     98   }
     99 
    100   return NULL;
    101 }
    102 
    103 
    104 /**
    105   This function will save confidential information to lockbox.
    106 
    107   @param Guid       the guid to identify the confidential information
    108   @param Buffer     the address of the confidential information
    109   @param Length     the length of the confidential information
    110 
    111   @retval RETURN_SUCCESS            the information is saved successfully.
    112   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or
    113                                     Length is 0
    114   @retval RETURN_ALREADY_STARTED    the requested GUID already exist.
    115   @retval RETURN_OUT_OF_RESOURCES   no enough resource to save the information.
    116   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
    117   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
    118   @retval RETURN_UNSUPPORTED        the service is not supported by
    119                                     implementaion.
    120 **/
    121 RETURN_STATUS
    122 EFIAPI
    123 SaveLockBox (
    124   IN  GUID                        *Guid,
    125   IN  VOID                        *Buffer,
    126   IN  UINTN                       Length
    127   )
    128 {
    129   LOCK_BOX_ENTRY *Header;
    130   VOID            *CopyBuffer;
    131 
    132   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p Length=0x%x\n", __FUNCTION__,
    133     Guid, Buffer, (UINT32) Length));
    134 
    135   if (Guid == NULL || Buffer == NULL || Length == 0) {
    136     return RETURN_INVALID_PARAMETER;
    137   }
    138 
    139   if (Length > 0xFFFFFFFF) {
    140     return RETURN_OUT_OF_RESOURCES;
    141   }
    142 
    143   Header = FindHeaderByGuid (Guid);
    144   if (Header == NULL) {
    145     return RETURN_OUT_OF_RESOURCES;
    146   }
    147 
    148   if (Header->Size > 0) {
    149     return RETURN_ALREADY_STARTED;
    150   }
    151 
    152   CopyBuffer = AllocateAcpiNvsPool (Length);
    153   if (CopyBuffer == NULL) {
    154     return RETURN_OUT_OF_RESOURCES;
    155   }
    156 
    157   //
    158   // overwrite the current terminator header with new metadata
    159   //
    160   CopyGuid (&Header->Guid, Guid);
    161   Header->OrigAddress = (UINTN) Buffer;
    162   Header->CopyAddress = (UINTN) CopyBuffer;
    163   Header->Size        = (UINT32) Length;
    164   Header->Attributes  = 0;
    165 
    166   //
    167   // copy contents
    168   //
    169   CopyMem (CopyBuffer, Buffer, Length);
    170 
    171   return RETURN_SUCCESS;
    172 }
    173 
    174 
    175 /**
    176   This function will set lockbox attributes.
    177 
    178   @param Guid       the guid to identify the confidential information
    179   @param Attributes the attributes of the lockbox
    180 
    181   @retval RETURN_SUCCESS            the information is saved successfully.
    182   @retval RETURN_INVALID_PARAMETER  attributes is invalid.
    183   @retval RETURN_NOT_FOUND          the requested GUID not found.
    184   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
    185   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
    186   @retval RETURN_UNSUPPORTED        the service is not supported by
    187                                     implementaion.
    188 **/
    189 RETURN_STATUS
    190 EFIAPI
    191 SetLockBoxAttributes (
    192   IN  GUID                        *Guid,
    193   IN  UINT64                      Attributes
    194   )
    195 {
    196   LOCK_BOX_ENTRY *Header;
    197 
    198   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Attributes=0x%Lx\n", __FUNCTION__, Guid,
    199     Attributes));
    200 
    201   if (Guid == NULL) {
    202     return RETURN_INVALID_PARAMETER;
    203   }
    204 
    205   Header = FindHeaderByGuid (Guid);
    206   if (!Header || Header->Size == 0) {
    207     return RETURN_NOT_FOUND;
    208   }
    209   Header->Attributes = Attributes;
    210 
    211   return RETURN_SUCCESS;
    212 }
    213 
    214 
    215 /**
    216   This function will update confidential information to lockbox.
    217 
    218   @param Guid   the guid to identify the original confidential information
    219   @param Offset the offset of the original confidential information
    220   @param Buffer the address of the updated confidential information
    221   @param Length the length of the updated confidential information
    222 
    223   @retval RETURN_SUCCESS            the information is saved successfully.
    224   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or
    225                                     Length is 0.
    226   @retval RETURN_NOT_FOUND          the requested GUID not found.
    227   @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold
    228                                     new information.
    229   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
    230   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
    231   @retval RETURN_UNSUPPORTED        the service is not supported by
    232                                     implementaion.
    233 **/
    234 RETURN_STATUS
    235 EFIAPI
    236 UpdateLockBox (
    237   IN  GUID                        *Guid,
    238   IN  UINTN                       Offset,
    239   IN  VOID                        *Buffer,
    240   IN  UINTN                       Length
    241   )
    242 {
    243   LOCK_BOX_ENTRY *Header;
    244 
    245   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Offset=0x%x Length=0x%x\n", __FUNCTION__,
    246     Guid, (UINT32) Offset, (UINT32) Length));
    247 
    248   if (Guid == NULL || Buffer == NULL || Length == 0) {
    249     return RETURN_INVALID_PARAMETER;
    250   }
    251 
    252   Header = FindHeaderByGuid (Guid);
    253   if (!Header || Header->Size == 0) {
    254     return RETURN_NOT_FOUND;
    255   }
    256 
    257   if (Header->Size < Offset ||
    258       Length > Header->Size - Offset) {
    259     return RETURN_BUFFER_TOO_SMALL;
    260   }
    261 
    262   CopyMem ((UINT8 *)(UINTN) (Header->CopyAddress) + Offset, Buffer, Length);
    263 
    264   return RETURN_SUCCESS;
    265 }
    266 
    267 
    268 /**
    269   This function will restore confidential information from lockbox.
    270 
    271   @param Guid   the guid to identify the confidential information
    272   @param Buffer the address of the restored confidential information
    273                 NULL means restored to original address, Length MUST be NULL at
    274                 same time.
    275   @param Length the length of the restored confidential information
    276 
    277   @retval RETURN_SUCCESS            the information is restored successfully.
    278   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or one of Buffer and
    279                                     Length is NULL.
    280   @retval RETURN_WRITE_PROTECTED    Buffer and Length are NULL, but the LockBox
    281                                     has no LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
    282                                     attribute.
    283   @retval RETURN_BUFFER_TOO_SMALL   the Length is too small to hold the
    284                                     confidential information.
    285   @retval RETURN_NOT_FOUND          the requested GUID not found.
    286   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
    287   @retval RETURN_ACCESS_DENIED      not allow to restore to the address
    288   @retval RETURN_UNSUPPORTED        the service is not supported by
    289                                     implementaion.
    290 **/
    291 RETURN_STATUS
    292 EFIAPI
    293 RestoreLockBox (
    294   IN  GUID                        *Guid,
    295   IN  VOID                        *Buffer, OPTIONAL
    296   IN  OUT UINTN                   *Length  OPTIONAL
    297   )
    298 {
    299   LOCK_BOX_ENTRY *Header;
    300 
    301   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__, Guid,
    302     Buffer));
    303 
    304   if ((Guid == NULL) ||
    305       ((Buffer == NULL) && (Length != NULL)) ||
    306       ((Buffer != NULL) && (Length == NULL))) {
    307     return EFI_INVALID_PARAMETER;
    308   }
    309 
    310   Header = FindHeaderByGuid (Guid);
    311   if (!Header || Header->Size == 0) {
    312     return RETURN_NOT_FOUND;
    313   }
    314 
    315   if (Buffer == NULL) {
    316     if (!(Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE)) {
    317       return RETURN_WRITE_PROTECTED;
    318     }
    319     if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {
    320       return RETURN_UNSUPPORTED;
    321     }
    322     Buffer = (VOID *)(UINTN) Header->OrigAddress;
    323   }
    324 
    325   //
    326   // Set RestoreLength
    327   //
    328   if (Length != NULL) {
    329     if (Header->Size > *Length) {
    330       //
    331       // Input buffer is too small to hold all data.
    332       //
    333       *Length = Header->Size;
    334       return EFI_BUFFER_TOO_SMALL;
    335     }
    336     *Length = Header->Size;
    337   }
    338 
    339   CopyMem (Buffer, (VOID*)(UINTN) Header->CopyAddress, Header->Size);
    340 
    341   return RETURN_SUCCESS;
    342 }
    343 
    344 
    345 /**
    346   This function will restore confidential information from all lockbox which
    347   have RestoreInPlace attribute.
    348 
    349   @retval RETURN_SUCCESS            the information is restored successfully.
    350   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
    351   @retval RETURN_UNSUPPORTED        the service is not supported by
    352                                     implementaion.
    353 **/
    354 RETURN_STATUS
    355 EFIAPI
    356 RestoreAllLockBoxInPlace (
    357   VOID
    358   )
    359 {
    360   LOCK_BOX_ENTRY *Header;
    361 
    362   for (Header = StartOfEntries;
    363        Header < EndOfEntries && Header->Size > 0;
    364        Header++) {
    365     if (Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) {
    366       VOID *Buffer;
    367 
    368       if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {
    369         return RETURN_UNSUPPORTED;
    370       }
    371       Buffer = (VOID *)(UINTN) Header->OrigAddress;
    372       CopyMem (Buffer, (VOID*)(UINTN)Header->CopyAddress, Header->Size);
    373       DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__,
    374         &Header->Guid, Buffer));
    375     }
    376   }
    377   return RETURN_SUCCESS;
    378 }
    379