Home | History | Annotate | Download | only in SmmLockBox
      1 /** @file
      2   LockBox SMM driver.
      3 
      4   Caution: This module requires additional review when modified.
      5   This driver will have external input - communicate buffer in SMM mode.
      6   This external input must be validated carefully to avoid security issue like
      7   buffer overflow, integer overflow.
      8 
      9   SmmLockBoxHandler(), SmmLockBoxRestore(), SmmLockBoxUpdate(), SmmLockBoxSave()
     10   will receive untrusted input and do basic validation.
     11 
     12 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
     13 
     14 This program and the accompanying materials
     15 are licensed and made available under the terms and conditions
     16 of the BSD License which accompanies this distribution.  The
     17 full text of the license may be found at
     18 http://opensource.org/licenses/bsd-license.php
     19 
     20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     22 
     23 **/
     24 
     25 #include <PiSmm.h>
     26 #include <Library/UefiDriverEntryPoint.h>
     27 #include <Library/UefiBootServicesTableLib.h>
     28 #include <Library/UefiRuntimeServicesTableLib.h>
     29 #include <Library/SmmServicesTableLib.h>
     30 #include <Library/BaseLib.h>
     31 #include <Library/BaseMemoryLib.h>
     32 #include <Library/DebugLib.h>
     33 #include <Library/SmmMemLib.h>
     34 #include <Library/LockBoxLib.h>
     35 
     36 #include <Protocol/SmmReadyToLock.h>
     37 #include <Protocol/SmmCommunication.h>
     38 #include <Protocol/LockBox.h>
     39 #include <Guid/SmmLockBox.h>
     40 
     41 BOOLEAN              mLocked = FALSE;
     42 
     43 /**
     44   Dispatch function for SMM lock box save.
     45 
     46   Caution: This function may receive untrusted input.
     47   Restore buffer and length are external input, so this function will validate
     48   it is in SMRAM.
     49 
     50   @param LockBoxParameterSave  parameter of lock box save
     51 **/
     52 VOID
     53 SmmLockBoxSave (
     54   IN EFI_SMM_LOCK_BOX_PARAMETER_SAVE *LockBoxParameterSave
     55   )
     56 {
     57   EFI_STATUS                  Status;
     58   EFI_SMM_LOCK_BOX_PARAMETER_SAVE TempLockBoxParameterSave;
     59 
     60   //
     61   // Sanity check
     62   //
     63   if (mLocked) {
     64     DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
     65     LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
     66     return ;
     67   }
     68 
     69   CopyMem (&TempLockBoxParameterSave, LockBoxParameterSave, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SAVE));
     70 
     71   //
     72   // Sanity check
     73   //
     74   if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterSave.Buffer, (UINTN)TempLockBoxParameterSave.Length)) {
     75     DEBUG ((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n"));
     76     LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
     77     return ;
     78   }
     79 
     80   //
     81   // Save data
     82   //
     83   Status = SaveLockBox (
     84              &TempLockBoxParameterSave.Guid,
     85              (VOID *)(UINTN)TempLockBoxParameterSave.Buffer,
     86              (UINTN)TempLockBoxParameterSave.Length
     87              );
     88   LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status;
     89   return ;
     90 }
     91 
     92 /**
     93   Dispatch function for SMM lock box set attributes.
     94 
     95   @param LockBoxParameterSetAttributes  parameter of lock box set attributes
     96 **/
     97 VOID
     98 SmmLockBoxSetAttributes (
     99   IN EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes
    100   )
    101 {
    102   EFI_STATUS                    Status;
    103   EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES TempLockBoxParameterSetAttributes;
    104 
    105   //
    106   // Sanity check
    107   //
    108   if (mLocked) {
    109     DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
    110     LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
    111     return ;
    112   }
    113 
    114   CopyMem (&TempLockBoxParameterSetAttributes, LockBoxParameterSetAttributes, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES));
    115 
    116   //
    117   // Update data
    118   //
    119   Status = SetLockBoxAttributes (
    120              &TempLockBoxParameterSetAttributes.Guid,
    121              TempLockBoxParameterSetAttributes.Attributes
    122              );
    123   LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status;
    124   return ;
    125 }
    126 
    127 /**
    128   Dispatch function for SMM lock box update.
    129 
    130   Caution: This function may receive untrusted input.
    131   Restore buffer and length are external input, so this function will validate
    132   it is in SMRAM.
    133 
    134   @param LockBoxParameterUpdate  parameter of lock box update
    135 **/
    136 VOID
    137 SmmLockBoxUpdate (
    138   IN EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate
    139   )
    140 {
    141   EFI_STATUS                    Status;
    142   EFI_SMM_LOCK_BOX_PARAMETER_UPDATE TempLockBoxParameterUpdate;
    143 
    144   //
    145   // Sanity check
    146   //
    147   if (mLocked) {
    148     DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
    149     LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
    150     return ;
    151   }
    152 
    153   CopyMem (&TempLockBoxParameterUpdate, LockBoxParameterUpdate, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE));
    154 
    155   //
    156   // Sanity check
    157   //
    158   if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterUpdate.Buffer, (UINTN)TempLockBoxParameterUpdate.Length)) {
    159     DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));
    160     LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
    161     return ;
    162   }
    163 
    164   //
    165   // Update data
    166   //
    167   Status = UpdateLockBox (
    168              &TempLockBoxParameterUpdate.Guid,
    169              (UINTN)TempLockBoxParameterUpdate.Offset,
    170              (VOID *)(UINTN)TempLockBoxParameterUpdate.Buffer,
    171              (UINTN)TempLockBoxParameterUpdate.Length
    172              );
    173   LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status;
    174   return ;
    175 }
    176 
    177 /**
    178   Dispatch function for SMM lock box restore.
    179 
    180   Caution: This function may receive untrusted input.
    181   Restore buffer and length are external input, so this function will validate
    182   it is in SMRAM.
    183 
    184   @param LockBoxParameterRestore  parameter of lock box restore
    185 **/
    186 VOID
    187 SmmLockBoxRestore (
    188   IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore
    189   )
    190 {
    191   EFI_STATUS                     Status;
    192   EFI_SMM_LOCK_BOX_PARAMETER_RESTORE TempLockBoxParameterRestore;
    193 
    194   CopyMem (&TempLockBoxParameterRestore, LockBoxParameterRestore, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE));
    195 
    196   //
    197   // Sanity check
    198   //
    199   if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterRestore.Buffer, (UINTN)TempLockBoxParameterRestore.Length)) {
    200     DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));
    201     LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
    202     return ;
    203   }
    204 
    205   //
    206   // Restore data
    207   //
    208   if ((TempLockBoxParameterRestore.Length == 0) && (TempLockBoxParameterRestore.Buffer == 0)) {
    209     Status = RestoreLockBox (
    210                &TempLockBoxParameterRestore.Guid,
    211                NULL,
    212                NULL
    213                );
    214   } else {
    215     Status = RestoreLockBox (
    216                &TempLockBoxParameterRestore.Guid,
    217                (VOID *)(UINTN)TempLockBoxParameterRestore.Buffer,
    218                (UINTN *)&TempLockBoxParameterRestore.Length
    219                );
    220   }
    221   LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
    222   return ;
    223 }
    224 
    225 /**
    226   Dispatch function for SMM lock box restore all in place.
    227 
    228   @param LockBoxParameterRestoreAllInPlace  parameter of lock box restore all in place
    229 **/
    230 VOID
    231 SmmLockBoxRestoreAllInPlace (
    232   IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace
    233   )
    234 {
    235   EFI_STATUS                     Status;
    236 
    237   Status = RestoreAllLockBoxInPlace ();
    238   LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;
    239   return ;
    240 }
    241 
    242 /**
    243   Dispatch function for a Software SMI handler.
    244 
    245   Caution: This function may receive untrusted input.
    246   Communicate buffer and buffer size are external input, so this function will do basic validation.
    247 
    248   @param DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
    249   @param Context         Points to an optional handler context which was specified when the
    250                          handler was registered.
    251   @param CommBuffer      A pointer to a collection of data in memory that will
    252                          be conveyed from a non-SMM environment into an SMM environment.
    253   @param CommBufferSize  The size of the CommBuffer.
    254 
    255   @retval EFI_SUCCESS Command is handled successfully.
    256 
    257 **/
    258 EFI_STATUS
    259 EFIAPI
    260 SmmLockBoxHandler (
    261   IN EFI_HANDLE  DispatchHandle,
    262   IN CONST VOID  *Context         OPTIONAL,
    263   IN OUT VOID    *CommBuffer      OPTIONAL,
    264   IN OUT UINTN   *CommBufferSize  OPTIONAL
    265   )
    266 {
    267   EFI_SMM_LOCK_BOX_PARAMETER_HEADER *LockBoxParameterHeader;
    268   UINTN                             TempCommBufferSize;
    269 
    270   DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Enter\n"));
    271 
    272   //
    273   // If input is invalid, stop processing this SMI
    274   //
    275   if (CommBuffer == NULL || CommBufferSize == NULL) {
    276     return EFI_SUCCESS;
    277   }
    278 
    279   TempCommBufferSize = *CommBufferSize;
    280 
    281   //
    282   // Sanity check
    283   //
    284   if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_HEADER)) {
    285     DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size invalid!\n"));
    286     return EFI_SUCCESS;
    287   }
    288   if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
    289     DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer in SMRAM or overflow!\n"));
    290     return EFI_SUCCESS;
    291   }
    292 
    293   LockBoxParameterHeader = (EFI_SMM_LOCK_BOX_PARAMETER_HEADER *)((UINTN)CommBuffer);
    294 
    295   LockBoxParameterHeader->ReturnStatus = (UINT64)-1;
    296 
    297   DEBUG ((EFI_D_ERROR, "SmmLockBox LockBoxParameterHeader - %x\n", (UINTN)LockBoxParameterHeader));
    298 
    299   DEBUG ((EFI_D_ERROR, "SmmLockBox Command - %x\n", (UINTN)LockBoxParameterHeader->Command));
    300 
    301   switch (LockBoxParameterHeader->Command) {
    302   case EFI_SMM_LOCK_BOX_COMMAND_SAVE:
    303     if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)) {
    304       DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SAVE invalid!\n"));
    305       break;
    306     }
    307     SmmLockBoxSave ((EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)(UINTN)LockBoxParameterHeader);
    308     break;
    309   case EFI_SMM_LOCK_BOX_COMMAND_UPDATE:
    310     if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)) {
    311       DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for UPDATE invalid!\n"));
    312       break;
    313     }
    314     SmmLockBoxUpdate ((EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)LockBoxParameterHeader);
    315     break;
    316   case EFI_SMM_LOCK_BOX_COMMAND_RESTORE:
    317     if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)) {
    318       DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE invalid!\n"));
    319       break;
    320     }
    321     SmmLockBoxRestore ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)(UINTN)LockBoxParameterHeader);
    322     break;
    323   case EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES:
    324     if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)) {
    325       DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SET_ATTRIBUTES invalid!\n"));
    326       break;
    327     }
    328     SmmLockBoxSetAttributes ((EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)(UINTN)LockBoxParameterHeader);
    329     break;
    330   case EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE:
    331     if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)) {
    332       DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE_ALL_IN_PLACE invalid!\n"));
    333       break;
    334     }
    335     SmmLockBoxRestoreAllInPlace ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)(UINTN)LockBoxParameterHeader);
    336     break;
    337   default:
    338     DEBUG ((EFI_D_ERROR, "SmmLockBox Command invalid!\n"));
    339     break;
    340   }
    341 
    342   LockBoxParameterHeader->Command = (UINT32)-1;
    343 
    344   DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Exit\n"));
    345 
    346   return EFI_SUCCESS;
    347 }
    348 
    349 /**
    350   Smm Ready To Lock event notification handler.
    351 
    352   It sets a flag indicating that SMRAM has been locked.
    353 
    354   @param[in] Protocol   Points to the protocol's unique identifier.
    355   @param[in] Interface  Points to the interface instance.
    356   @param[in] Handle     The handle on which the interface was installed.
    357 
    358   @retval EFI_SUCCESS   Notification handler runs successfully.
    359  **/
    360 EFI_STATUS
    361 EFIAPI
    362 SmmReadyToLockEventNotify (
    363   IN CONST EFI_GUID  *Protocol,
    364   IN VOID            *Interface,
    365   IN EFI_HANDLE      Handle
    366   )
    367 {
    368   mLocked = TRUE;
    369   return EFI_SUCCESS;
    370 }
    371 
    372 /**
    373   Entry Point for LockBox SMM driver.
    374 
    375   @param[in] ImageHandle  Image handle of this driver.
    376   @param[in] SystemTable  A Pointer to the EFI System Table.
    377 
    378   @retval EFI_SUCEESS
    379   @return Others          Some error occurs.
    380 **/
    381 EFI_STATUS
    382 EFIAPI
    383 SmmLockBoxEntryPoint (
    384   IN EFI_HANDLE        ImageHandle,
    385   IN EFI_SYSTEM_TABLE  *SystemTable
    386   )
    387 {
    388   EFI_STATUS                    Status;
    389   EFI_HANDLE                    DispatchHandle;
    390   VOID                          *Registration;
    391 
    392   //
    393   // Register LockBox communication handler
    394   //
    395   Status = gSmst->SmiHandlerRegister (
    396                     SmmLockBoxHandler,
    397                     &gEfiSmmLockBoxCommunicationGuid,
    398                     &DispatchHandle
    399                     );
    400   ASSERT_EFI_ERROR (Status);
    401 
    402   //
    403   // Register SMM Ready To Lock Protocol notification
    404   //
    405   Status = gSmst->SmmRegisterProtocolNotify (
    406                     &gEfiSmmReadyToLockProtocolGuid,
    407                     SmmReadyToLockEventNotify,
    408                     &Registration
    409                     );
    410   ASSERT_EFI_ERROR (Status);
    411 
    412   //
    413   // Install NULL to DXE data base as notify
    414   //
    415   ImageHandle = NULL;
    416   Status = gBS->InstallProtocolInterface (
    417                   &ImageHandle,
    418                   &gEfiLockBoxProtocolGuid,
    419                   EFI_NATIVE_INTERFACE,
    420                   NULL
    421                   );
    422   ASSERT_EFI_ERROR (Status);
    423 
    424   return Status;
    425 }
    426