]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Add comments to clarify mPubKeyStore buffer MemCopy. There is no memory overflow...
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / AuthService.c
index ee45ec97767de0e9b45b730f5e6cec97068170e1..566c5e29a7866cc4248f01fc56df13fed3e08816 100644 (file)
@@ -7,6 +7,10 @@
   This external input must be validated carefully to avoid security issue like\r
   buffer overflow, integer overflow.\r
   Variable attribute should also be checked to avoid authentication bypass.\r
+     The whole SMM authentication variable design relies on the integrity of flash part and SMM.\r
+  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory\r
+  may not be modified without authorization. If platform fails to protect these resources, \r
+  the authentication service provided in this driver will be broken, and the behavior is undefined.\r
 \r
   ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r
   variable authentication.\r
@@ -15,7 +19,7 @@
   They will do basic validation for authentication data structure, then call crypto library\r
   to verify the signature.\r
 \r
-Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -32,9 +36,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 ///\r
 /// Global database array for scratch\r
 ///\r
-UINT8    mPubKeyStore[MAX_KEYDB_SIZE];\r
+UINT8    *mPubKeyStore;\r
 UINT32   mPubKeyNumber;\r
-UINT8    mCertDbStore[MAX_CERTDB_SIZE];\r
+UINT32   mMaxKeyNumber;\r
+UINT32   mMaxKeyDbSize;\r
+UINT8    *mCertDbStore;\r
+UINT32   mMaxCertDbSize;\r
 UINT32   mPlatformMode;\r
 UINT8    mVendorKeyState;\r
 \r
@@ -183,6 +190,25 @@ AutenticatedVariableServiceInitialize (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  //\r
+  // Reserve runtime buffer for public key database. The size excludes variable header and name size.\r
+  //\r
+  mMaxKeyDbSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - sizeof (AUTHVAR_KEYDB_NAME);\r
+  mMaxKeyNumber = mMaxKeyDbSize / EFI_CERT_TYPE_RSA2048_SIZE;\r
+  mPubKeyStore  = AllocateRuntimePool (mMaxKeyDbSize);\r
+  if (mPubKeyStore == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Reserve runtime buffer for certificate database. The size excludes variable header and name size.\r
+  //\r
+  mMaxCertDbSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - sizeof (EFI_CERT_DB_NAME);\r
+  mCertDbStore   = AllocateRuntimePool (mMaxCertDbSize);\r
+  if (mCertDbStore == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
   //\r
   // Prepare runtime buffer for serialized data of time-based authenticated\r
   // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
@@ -229,6 +255,10 @@ AutenticatedVariableServiceInitialize (
     DataSize  = DataSizeOfVariable (Variable.CurrPtr);\r
     Data      = GetVariableDataPtr (Variable.CurrPtr);\r
     ASSERT ((DataSize != 0) && (Data != NULL));\r
+    //\r
+    // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before) \r
+    //  Therefore, there is no memory overflow in underlying CopyMem.\r
+    //\r
     CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
     mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
   }\r
@@ -450,22 +480,26 @@ AutenticatedVariableServiceInitialize (
   Add public key in store and return its index.\r
 \r
   @param[in]  PubKey                  Input pointer to Public Key data\r
+  @param[in]  VariableDataEntry       The variable data entry \r
 \r
   @return                             Index of new added item\r
 \r
 **/\r
 UINT32\r
 AddPubKeyInStore (\r
-  IN  UINT8               *PubKey\r
+  IN  UINT8                        *PubKey,\r
+  IN  VARIABLE_ENTRY_CONSISTENCY   *VariableDataEntry\r
   )\r
 {\r
-  EFI_STATUS              Status;\r
-  BOOLEAN                 IsFound;\r
-  UINT32                  Index;\r
-  VARIABLE_POINTER_TRACK  Variable;\r
-  UINT8                   *Ptr;\r
-  UINT8                   *Data;\r
-  UINTN                   DataSize;\r
+  EFI_STATUS                       Status;\r
+  BOOLEAN                          IsFound;\r
+  UINT32                           Index;\r
+  VARIABLE_POINTER_TRACK           Variable;\r
+  UINT8                            *Ptr;\r
+  UINT8                            *Data;\r
+  UINTN                            DataSize;\r
+  VARIABLE_ENTRY_CONSISTENCY       PublicKeyEntry;\r
+  UINT32                           Attributes;\r
 \r
   if (PubKey == NULL) {\r
     return 0;\r
@@ -478,8 +512,8 @@ AddPubKeyInStore (
              &mVariableModuleGlobal->VariableGlobal,\r
              FALSE\r
              );\r
-  ASSERT_EFI_ERROR (Status);\r
   if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));\r
     return 0;\r
   }\r
 \r
@@ -499,7 +533,7 @@ AddPubKeyInStore (
     //\r
     // Add public key in database.\r
     //\r
-    if (mPubKeyNumber == MAX_KEY_NUM) {\r
+    if (mPubKeyNumber == mMaxKeyNumber) {\r
       //\r
       // Public key dadatase is full, try to reclaim invalid key.\r
       //\r
@@ -530,22 +564,41 @@ AddPubKeyInStore (
                  &mVariableModuleGlobal->VariableGlobal,\r
                  FALSE\r
                  );\r
-      ASSERT_EFI_ERROR (Status);\r
       if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));\r
         return 0;\r
       }\r
 \r
       DataSize  = DataSizeOfVariable (Variable.CurrPtr);\r
       Data      = GetVariableDataPtr (Variable.CurrPtr);\r
       ASSERT ((DataSize != 0) && (Data != NULL));\r
+      //\r
+      // "AuthVarKeyDatabase" is an internal used variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before) \r
+      //  Therefore, there is no memory overflow in underlying CopyMem.\r
+      //\r
       CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
       mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
 \r
-      if (mPubKeyNumber == MAX_KEY_NUM) {\r
+      if (mPubKeyNumber == mMaxKeyNumber) {\r
         return 0;\r
       }     \r
     }\r
 \r
+    //\r
+    // Check the variable space for both public key and variable data.\r
+    //\r
+    PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * EFI_CERT_TYPE_RSA2048_SIZE;\r
+    PublicKeyEntry.Guid         = &gEfiAuthenticatedVariableGuid;\r
+    PublicKeyEntry.Name         = AUTHVAR_KEYDB_NAME;\r
+    Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+\r
+    if (!CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {\r
+      //\r
+      // No enough variable space.\r
+      //\r
+      return 0;\r
+    }\r
+\r
     CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
     Index = ++mPubKeyNumber;\r
     //\r
@@ -556,13 +609,16 @@ AddPubKeyInStore (
                &gEfiAuthenticatedVariableGuid,\r
                mPubKeyStore,\r
                mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
-               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
+               Attributes,\r
                0,\r
                0,\r
                &Variable,\r
                NULL\r
                );\r
-    ASSERT_EFI_ERROR (Status);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));\r
+      return 0;\r
+    }\r
   }\r
 \r
   return Index;\r
@@ -1268,6 +1324,7 @@ ProcessVariable (
   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
   UINT32                          KeyIndex;\r
   UINT64                          MonotonicCount;\r
+  VARIABLE_ENTRY_CONSISTENCY      VariableDataEntry;\r
 \r
   KeyIndex    = 0;\r
   CertData    = NULL;\r
@@ -1365,9 +1422,11 @@ ProcessVariable (
 \r
   if (!IsFirstTime) {\r
     //\r
-    // Check input PubKey.\r
+    // 2 cases need to check here\r
+    //   1. Internal PubKey variable. PubKeyIndex is always 0 \r
+    //   2. Other counter-based AuthVariable. Check input PubKey.\r
     //\r
-    if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
+    if (KeyIndex == 0 || CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
       return EFI_SECURITY_VIOLATION;\r
     }\r
     //\r
@@ -1393,10 +1452,14 @@ ProcessVariable (
   // Now, the signature has been verified!\r
   //\r
   if (IsFirstTime && !IsDeletion) {\r
+    VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;\r
+    VariableDataEntry.Guid         = VendorGuid;\r
+    VariableDataEntry.Name         = VariableName;\r
+\r
     //\r
     // Update public key database variable if need.\r
     //\r
-    KeyIndex = AddPubKeyInStore (PubKey);\r
+    KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);\r
     if (KeyIndex == 0) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
@@ -1969,7 +2032,7 @@ InsertCertsToDb (
   NameSize      = (UINT32) StrLen (VariableName);\r
   CertNodeSize  = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16); \r
   NewCertDbSize = (UINT32) DataSize + CertNodeSize;\r
-  if (NewCertDbSize > MAX_CERTDB_SIZE) {\r
+  if (NewCertDbSize > mMaxCertDbSize) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
   NewCertDb     = (UINT8*) mCertDbStore;\r
@@ -2095,6 +2158,7 @@ VerifyTimeBasedPayload (
   WrapSigData            = NULL;\r
   SignerCerts            = NULL;\r
   RootCert               = NULL;\r
+  CertsInCertDb          = NULL;\r
 \r
   //\r
   // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r