Home | History | Annotate | Download | only in RuntimeDxe
      1 /** @file
      2   TCG MOR (Memory Overwrite Request) Lock Control support (SMM version).
      3 
      4   This module initilizes MemoryOverwriteRequestControlLock variable.
      5   This module adds Variable Hook and check MemoryOverwriteRequestControlLock.
      6 
      7 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this 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,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include <PiDxe.h>
     19 #include <Guid/MemoryOverwriteControl.h>
     20 #include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/BaseLib.h>
     23 #include <Library/BaseMemoryLib.h>
     24 #include "Variable.h"
     25 
     26 typedef struct {
     27   CHAR16                                 *VariableName;
     28   EFI_GUID                               *VendorGuid;
     29 } VARIABLE_TYPE;
     30 
     31 VARIABLE_TYPE  mMorVariableType[] = {
     32   {MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,      &gEfiMemoryOverwriteControlDataGuid},
     33   {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,  &gEfiMemoryOverwriteRequestControlLockGuid},
     34 };
     35 
     36 #define MOR_LOCK_DATA_UNLOCKED           0x0
     37 #define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY 0x1
     38 #define MOR_LOCK_DATA_LOCKED_WITH_KEY    0x2
     39 
     40 #define MOR_LOCK_V1_SIZE      1
     41 #define MOR_LOCK_V2_KEY_SIZE  8
     42 
     43 typedef enum {
     44   MorLockStateUnlocked = 0,
     45   MorLockStateLocked = 1,
     46 } MOR_LOCK_STATE;
     47 
     48 UINT8           mMorLockKey[MOR_LOCK_V2_KEY_SIZE];
     49 BOOLEAN         mMorLockKeyEmpty = TRUE;
     50 BOOLEAN         mMorLockPassThru = FALSE;
     51 MOR_LOCK_STATE  mMorLockState = MorLockStateUnlocked;
     52 
     53 /**
     54   Returns if this is MOR related variable.
     55 
     56   @param  VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
     57   @param  VendorGuid   Unify identifier for vendor.
     58 
     59   @retval  TRUE            The variable is MOR related.
     60   @retval  FALSE           The variable is NOT MOR related.
     61 **/
     62 BOOLEAN
     63 IsAnyMorVariable (
     64   IN CHAR16                                 *VariableName,
     65   IN EFI_GUID                               *VendorGuid
     66   )
     67 {
     68   UINTN   Index;
     69 
     70   for (Index = 0; Index < sizeof(mMorVariableType)/sizeof(mMorVariableType[0]); Index++) {
     71     if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) == 0) &&
     72         (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid))) {
     73       return TRUE;
     74     }
     75   }
     76   return FALSE;
     77 }
     78 
     79 /**
     80   Returns if this is MOR lock variable.
     81 
     82   @param  VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
     83   @param  VendorGuid   Unify identifier for vendor.
     84 
     85   @retval  TRUE            The variable is MOR lock variable.
     86   @retval  FALSE           The variable is NOT MOR lock variable.
     87 **/
     88 BOOLEAN
     89 IsMorLockVariable (
     90   IN CHAR16                                 *VariableName,
     91   IN EFI_GUID                               *VendorGuid
     92   )
     93 {
     94   if ((StrCmp (VariableName, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) == 0) &&
     95       (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid))) {
     96     return TRUE;
     97   }
     98   return FALSE;
     99 }
    100 
    101 /**
    102   Set MOR lock variable.
    103 
    104   @param  Data         MOR Lock variable data.
    105 
    106   @retval  EFI_SUCCESS            The firmware has successfully stored the variable and its data as
    107                                   defined by the Attributes.
    108   @retval  EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the
    109                                   DataSize exceeds the maximum allowed.
    110   @retval  EFI_INVALID_PARAMETER  VariableName is an empty Unicode string.
    111   @retval  EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
    112   @retval  EFI_DEVICE_ERROR       The variable could not be saved due to a hardware failure.
    113   @retval  EFI_WRITE_PROTECTED    The variable in question is read-only.
    114   @retval  EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
    115   @retval  EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
    116                                   set but the AuthInfo does NOT pass the validation check carried
    117                                   out by the firmware.
    118   @retval  EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
    119 **/
    120 EFI_STATUS
    121 SetMorLockVariable (
    122   IN UINT8  Data
    123   )
    124 {
    125   EFI_STATUS  Status;
    126 
    127   mMorLockPassThru = TRUE;
    128   Status = VariableServiceSetVariable (
    129              MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
    130              &gEfiMemoryOverwriteRequestControlLockGuid,
    131              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    132              sizeof(Data),
    133              &Data
    134              );
    135   mMorLockPassThru = FALSE;
    136   return Status;
    137 }
    138 
    139 /**
    140   This service is an MorLock checker handler for the SetVariable().
    141 
    142   @param  VariableName the name of the vendor's variable, as a
    143                        Null-Terminated Unicode String
    144   @param  VendorGuid   Unify identifier for vendor.
    145   @param  Attributes   Point to memory location to return the attributes of variable. If the point
    146                        is NULL, the parameter would be ignored.
    147   @param  DataSize     The size in bytes of Data-Buffer.
    148   @param  Data         Point to the content of the variable.
    149 
    150   @retval  EFI_SUCCESS            The MorLock check pass, and Variable driver can store the variable data.
    151   @retval  EFI_INVALID_PARAMETER  The MorLock data or data size or attributes is not allowed.
    152   @retval  EFI_ACCESS_DENIED      The MorLock is locked.
    153   @retval  EFI_WRITE_PROTECTED    The MorLock deletion is not allowed.
    154   @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this function.
    155                                   Variable driver can just return EFI_SUCCESS.
    156 **/
    157 EFI_STATUS
    158 SetVariableCheckHandlerMorLock (
    159   IN CHAR16     *VariableName,
    160   IN EFI_GUID   *VendorGuid,
    161   IN UINT32     Attributes,
    162   IN UINTN      DataSize,
    163   IN VOID       *Data
    164   )
    165 {
    166   EFI_STATUS  Status;
    167 
    168   //
    169   // Basic Check
    170   //
    171   if (Attributes == 0 || DataSize == 0 || Data == NULL) {
    172     return EFI_WRITE_PROTECTED;
    173   }
    174 
    175   if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
    176       ((DataSize != MOR_LOCK_V1_SIZE) && (DataSize != MOR_LOCK_V2_KEY_SIZE))) {
    177     return EFI_INVALID_PARAMETER;
    178   }
    179 
    180   //
    181   // Do not check if the request is passthru.
    182   //
    183   if (mMorLockPassThru) {
    184     return EFI_SUCCESS;
    185   }
    186 
    187   if (mMorLockState == MorLockStateUnlocked) {
    188     //
    189     // In Unlocked State
    190     //
    191     if (DataSize == MOR_LOCK_V1_SIZE) {
    192       //
    193       // V1 - lock permanently
    194       //
    195       if (*(UINT8 *)Data == MOR_LOCK_DATA_UNLOCKED) {
    196         //
    197         // Unlock
    198         //
    199         Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
    200         if (!EFI_ERROR (Status)) {
    201           //
    202           // return EFI_ALREADY_STARTED to skip variable set.
    203           //
    204           return EFI_ALREADY_STARTED;
    205         } else {
    206           //
    207           // SetVar fail
    208           //
    209           return Status;
    210         }
    211       } else if (*(UINT8 *)Data == MOR_LOCK_DATA_LOCKED_WITHOUT_KEY) {
    212         //
    213         // Lock without key
    214         //
    215         Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITHOUT_KEY);
    216         if (!EFI_ERROR (Status)) {
    217           //
    218           // Lock success
    219           //
    220           mMorLockState = MorLockStateLocked;
    221           //
    222           // return EFI_ALREADY_STARTED to skip variable set.
    223           //
    224           return EFI_ALREADY_STARTED;
    225         } else {
    226           //
    227           // SetVar fail
    228           //
    229           return Status;
    230         }
    231       } else {
    232         return EFI_INVALID_PARAMETER;
    233       }
    234     } else if (DataSize == MOR_LOCK_V2_KEY_SIZE) {
    235       //
    236       // V2 lock and provision the key
    237       //
    238 
    239       //
    240       // Need set here because the data value on flash is different
    241       //
    242       Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITH_KEY);
    243       if (EFI_ERROR(Status)) {
    244         //
    245         // SetVar fail, do not provision the key
    246         //
    247         return Status;
    248       } else {
    249         //
    250         // Lock success, provision the key
    251         //
    252         mMorLockKeyEmpty = FALSE;
    253         CopyMem (mMorLockKey, Data, MOR_LOCK_V2_KEY_SIZE);
    254         mMorLockState = MorLockStateLocked;
    255         //
    256         // return EFI_ALREADY_STARTED to skip variable set.
    257         //
    258         return EFI_ALREADY_STARTED;
    259       }
    260     } else {
    261       ASSERT (FALSE);
    262       return EFI_OUT_OF_RESOURCES;
    263     }
    264   } else {
    265     //
    266     // In Locked State
    267     //
    268     if (mMorLockKeyEmpty || (DataSize != MOR_LOCK_V2_KEY_SIZE)) {
    269       return EFI_ACCESS_DENIED;
    270     }
    271     if ((CompareMem (Data, mMorLockKey, MOR_LOCK_V2_KEY_SIZE) == 0)) {
    272       //
    273       // Key match - unlock
    274       //
    275 
    276       //
    277       // Need set here because the data value on flash is different
    278       //
    279       Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
    280       if (EFI_ERROR (Status)) {
    281         //
    282         // SetVar fail
    283         //
    284         return Status;
    285       } else {
    286         //
    287         // Unlock Success
    288         //
    289         mMorLockState = MorLockStateUnlocked;
    290         mMorLockKeyEmpty = TRUE;
    291         ZeroMem (mMorLockKey, sizeof(mMorLockKey));
    292         //
    293         // return EFI_ALREADY_STARTED to skip variable set.
    294         //
    295         return EFI_ALREADY_STARTED;
    296       }
    297     } else {
    298       //
    299       // Key mismatch - Prevent Dictionary Attack
    300       //
    301       mMorLockState = MorLockStateLocked;
    302       mMorLockKeyEmpty = TRUE;
    303       ZeroMem (mMorLockKey, sizeof(mMorLockKey));
    304       return EFI_ACCESS_DENIED;
    305     }
    306   }
    307 }
    308 
    309 /**
    310   This service is an MOR/MorLock checker handler for the SetVariable().
    311 
    312   @param  VariableName the name of the vendor's variable, as a
    313                        Null-Terminated Unicode String
    314   @param  VendorGuid   Unify identifier for vendor.
    315   @param  Attributes   Point to memory location to return the attributes of variable. If the point
    316                        is NULL, the parameter would be ignored.
    317   @param  DataSize     The size in bytes of Data-Buffer.
    318   @param  Data         Point to the content of the variable.
    319 
    320   @retval  EFI_SUCCESS            The MOR/MorLock check pass, and Variable driver can store the variable data.
    321   @retval  EFI_INVALID_PARAMETER  The MOR/MorLock data or data size or attributes is not allowed for MOR variable.
    322   @retval  EFI_ACCESS_DENIED      The MOR/MorLock is locked.
    323   @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this function.
    324                                   Variable driver can just return EFI_SUCCESS.
    325 **/
    326 EFI_STATUS
    327 SetVariableCheckHandlerMor (
    328   IN CHAR16     *VariableName,
    329   IN EFI_GUID   *VendorGuid,
    330   IN UINT32     Attributes,
    331   IN UINTN      DataSize,
    332   IN VOID       *Data
    333   )
    334 {
    335   //
    336   // do not handle non-MOR variable
    337   //
    338   if (!IsAnyMorVariable (VariableName, VendorGuid)) {
    339     return EFI_SUCCESS;
    340   }
    341 
    342   //
    343   // MorLock variable
    344   //
    345   if (IsMorLockVariable (VariableName, VendorGuid)) {
    346     return SetVariableCheckHandlerMorLock (
    347              VariableName,
    348              VendorGuid,
    349              Attributes,
    350              DataSize,
    351              Data
    352              );
    353   }
    354 
    355   //
    356   // Mor Variable
    357   //
    358 
    359   //
    360   // Basic Check
    361   //
    362   if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
    363       (DataSize != sizeof(UINT8)) ||
    364       (Data == NULL)) {
    365     return EFI_INVALID_PARAMETER;
    366   }
    367   if (mMorLockState == MorLockStateLocked) {
    368     //
    369     // If lock, deny access
    370     //
    371     return EFI_ACCESS_DENIED;
    372   }
    373   //
    374   // grant access
    375   //
    376   return EFI_SUCCESS;
    377 }
    378 
    379 /**
    380   Initialization for MOR Lock Control.
    381 
    382   @retval EFI_SUCEESS     MorLock initialization success.
    383   @return Others          Some error occurs.
    384 **/
    385 EFI_STATUS
    386 MorLockInit (
    387   VOID
    388   )
    389 {
    390   //
    391   // Set variable to report capability to OS
    392   //
    393   return SetMorLockVariable (0);
    394 }
    395