+ @param[in] VariableName Name of variable.\r
+ @param[in] VendorGuid Guid of variable.\r
+ @param[in] Data Data pointer.\r
+ @param[in] DataSize Size of Data.\r
+ @param[in] Attributes Attribute value of the variable.\r
+ @param[in] TimeStamp Value of associated TimeStamp.\r
+\r
+ @retval EFI_SUCCESS The update operation is success.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalUpdateVariableWithTimeStamp (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN VOID *Data,\r
+ IN UINTN DataSize,\r
+ IN UINT32 Attributes,\r
+ IN EFI_TIME *TimeStamp\r
+ )\r
+{\r
+ EFI_STATUS FindStatus;\r
+ VOID *OrgData;\r
+ UINTN OrgDataSize;\r
+ AUTH_VARIABLE_INFO AuthVariableInfo;\r
+\r
+ FindStatus = AuthServiceInternalFindVariable (\r
+ VariableName,\r
+ VendorGuid,\r
+ &OrgData,\r
+ &OrgDataSize\r
+ );\r
+\r
+ //\r
+ // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable\r
+ //\r
+ if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {\r
+ if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
+ ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
+ (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||\r
+ (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r
+ //\r
+ // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of\r
+ // EFI_SIGNATURE_DATA values that are already part of the existing variable value.\r
+ //\r
+ FilterSignatureList (\r
+ OrgData,\r
+ OrgDataSize,\r
+ Data,\r
+ &DataSize\r
+ );\r
+ }\r
+ }\r
+\r
+ ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
+ AuthVariableInfo.VariableName = VariableName;\r
+ AuthVariableInfo.VendorGuid = VendorGuid;\r
+ AuthVariableInfo.Data = Data;\r
+ AuthVariableInfo.DataSize = DataSize;\r
+ AuthVariableInfo.Attributes = Attributes;\r
+ AuthVariableInfo.TimeStamp = TimeStamp;\r
+ return mAuthVarLibContextIn->UpdateVariable (\r
+ &AuthVariableInfo\r
+ );\r
+}\r
+\r
+/**\r
+ Initialize Secure Boot variables.\r
+\r
+ @retval EFI_SUCCESS The initialization operation is successful.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+InitSecureBootVariables (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *Data;\r
+ UINTN DataSize;\r
+ UINT32 SecureBoot;\r
+ UINT8 SecureBootEnable;\r
+ SECURE_BOOT_MODE_TYPE SecureBootMode;\r
+ BOOLEAN IsPkPresent;\r
+\r
+ //\r
+ // Find "PK" variable\r
+ //\r
+ Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);\r
+ if (EFI_ERROR (Status)) {\r
+ IsPkPresent = FALSE;\r
+ DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));\r
+ } else {\r
+ IsPkPresent = TRUE;\r
+ DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));\r
+ }\r
+\r
+ //\r
+ // Init "SecureBootMode" variable.\r
+ // Initial case\r
+ // SecureBootMode doesn't exist. Init it with PK state\r
+ // 3 inconsistency cases need to sync\r
+ // 1.1 Add PK -> system break -> update SecureBootMode Var\r
+ // 1.2 Delete PK -> system break -> update SecureBootMode Var\r
+ // 1.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var\r
+ //\r
+ Status = AuthServiceInternalFindVariable (EDKII_SECURE_BOOT_MODE_NAME, &gEdkiiSecureBootModeGuid, (VOID **)&Data, &DataSize);\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Variable driver Initial Case\r
+ //\r
+ if (IsPkPresent) {\r
+ SecureBootMode = SecureBootModeTypeUserMode;\r
+ } else {\r
+ SecureBootMode = SecureBootModeTypeSetupMode;\r
+ }\r
+ } else {\r
+ //\r
+ // 3 inconsistency cases need to sync\r
+ //\r
+ SecureBootMode = (SECURE_BOOT_MODE_TYPE)*Data;\r
+ ASSERT(SecureBootMode < SecureBootModeTypeMax);\r
+\r
+ if (IsPkPresent) {\r
+ //\r
+ // 3.1 Add PK -> system break -> update SecureBootMode Var\r
+ //\r
+ if (SecureBootMode == SecureBootModeTypeSetupMode) {\r
+ SecureBootMode = SecureBootModeTypeUserMode;\r
+ } else if (SecureBootMode == SecureBootModeTypeAuditMode) {\r
+ SecureBootMode = SecureBootModeTypeDeployedMode;\r
+ }\r
+ } else {\r
+ //\r
+ // 3.2 Delete PK -> system break -> update SecureBootMode Var\r
+ // 3.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var. Reinit to be SetupMode\r
+ //\r
+ if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {\r
+ SecureBootMode = SecureBootModeTypeSetupMode;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR(Status) || (SecureBootMode != (SECURE_BOOT_MODE_TYPE)*Data)) {\r
+ //\r
+ // Update SecureBootMode Var\r
+ //\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EDKII_SECURE_BOOT_MODE_NAME,\r
+ &gEdkiiSecureBootModeGuid,\r
+ &SecureBootMode,\r
+ sizeof (UINT8),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Init "AuditMode"\r
+ //\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EFI_AUDIT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &mSecureBootState[SecureBootMode].AuditMode,\r
+ sizeof(UINT8),\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Init "DeployedMode"\r
+ //\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EFI_DEPLOYED_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &mSecureBootState[SecureBootMode].DeployedMode,\r
+ sizeof(UINT8),\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Init "SetupMode"\r
+ //\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EFI_SETUP_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &mSecureBootState[SecureBootMode].SetupMode,\r
+ sizeof(UINT8),\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
+ // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in User Mode or Deployed Mode, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
+ // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
+ //\r
+ SecureBootEnable = SECURE_BOOT_DISABLE;\r
+ Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **)&Data, &DataSize);\r
+ if (!EFI_ERROR(Status)) {\r
+ if (!IsPkPresent) {\r
+ //\r
+ // PK is cleared in runtime. "SecureBootMode" is not updated before reboot\r
+ // Delete "SecureBootMode"\r
+ //\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ 0,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ } else {\r
+ SecureBootEnable = *Data;\r
+ }\r
+ } else if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {\r
+ //\r
+ // "SecureBootEnable" not exist, initialize it in User Mode or Deployed Mode.\r
+ //\r
+ SecureBootEnable = SECURE_BOOT_ENABLE;\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ sizeof (UINT8),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Create "SecureBoot" variable with BS+RT attribute set.\r
+ //\r
+ if ((SecureBootEnable == SECURE_BOOT_ENABLE) \r
+ && ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode))) {\r
+ SecureBoot = SECURE_BOOT_MODE_ENABLE;\r
+ } else {\r
+ SecureBoot = SECURE_BOOT_MODE_DISABLE;\r
+ }\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EFI_SECURE_BOOT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SecureBoot,\r
+ sizeof (UINT8),\r
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+\r
+ DEBUG ((EFI_D_INFO, "SecureBootMode is %x\n", SecureBootMode));\r
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBoot));\r
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));\r
+\r
+ //\r
+ // Save SecureBootMode in global space\r
+ //\r
+ mSecureBootMode = SecureBootMode;\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Update SecureBootMode variable.\r
+\r
+ @param[in] NewMode New Secure Boot Mode.\r
+\r
+ @retval EFI_SUCCESS The initialization operation is successful.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateSecureBootMode(\r
+ IN SECURE_BOOT_MODE_TYPE NewMode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Update "SecureBootMode" variable to new Secure Boot Mode\r
+ //\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EDKII_SECURE_BOOT_MODE_NAME,\r
+ &gEdkiiSecureBootModeGuid,\r
+ &NewMode,\r
+ sizeof (UINT8),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+ );\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_INFO, "SecureBootMode Update to %x\n", NewMode));\r
+ mSecureBootMode = NewMode;\r
+ } else {\r
+ DEBUG((EFI_D_ERROR, "SecureBootMode Update failure %x\n", Status));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Current secure boot mode is AuditMode. This function performs secure boot mode transition\r
+ to a new mode.\r
+\r
+ @param[in] NewMode New Secure Boot Mode.\r
+\r
+ @retval EFI_SUCCESS The initialization operation is successful.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+TransitionFromAuditMode(\r
+ IN SECURE_BOOT_MODE_TYPE NewMode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *AuditVarData;\r
+ UINT8 *DeployedVarData;\r
+ UINT8 *SetupVarData;\r
+ UINT8 *SecureBootVarData;\r
+ UINT8 SecureBootEnable;\r
+ UINTN DataSize;\r
+\r
+ //\r
+ // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
+ // they can be RW. but can't be deleted. so they can always be found.\r
+ //\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_AUDIT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &AuditVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_DEPLOYED_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &DeployedVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SETUP_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SetupVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SECURE_BOOT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SecureBootVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ //\r
+ // Make Secure Boot Mode transition ATOMIC\r
+ // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.\r
+ // other tranisition logic are all memory operations.\r
+ //\r
+ Status = UpdateSecureBootMode(NewMode);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
+ }\r
+\r
+ if (NewMode == SecureBootModeTypeDeployedMode) {\r
+ //\r
+ // Since PK is enrolled, can't rollback, always update SecureBootMode in memory\r
+ //\r
+ mSecureBootMode = NewMode;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // AuditMode ----> DeployedMode\r
+ // Side Effects\r
+ // AuditMode =: 0 / DeployedMode := 1 / SetupMode := 0\r
+ //\r
+ // Update the value of AuditMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));\r
+ //\r
+ // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
+ //\r
+ // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
+\r
+ if (mAuthVarLibContextIn->AtRuntime ()) {\r
+ //\r
+ // SecureBoot Variable indicates whether the platform firmware is operating\r
+ // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
+ // Variable in runtime.\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
+\r
+ //\r
+ // Create "SecureBootEnable" variable as secure boot is enabled.\r
+ //\r
+ SecureBootEnable = SECURE_BOOT_ENABLE;\r
+ AuthServiceInternalUpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ sizeof (SecureBootEnable),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ } else {\r
+ DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeAuditMode, NewMode));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Current secure boot mode is DeployedMode. This function performs secure boot mode transition\r
+ to a new mode.\r
+\r
+ @param[in] NewMode New Secure Boot Mode.\r
+\r
+ @retval EFI_SUCCESS The initialization operation is successful.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+TransitionFromDeployedMode(\r
+ IN SECURE_BOOT_MODE_TYPE NewMode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *DeployedVarData;\r
+ UINT8 *SetupVarData;\r
+ UINT8 *SecureBootVarData;\r
+ UINT8 SecureBootEnable;\r
+ UINTN DataSize;\r
+\r
+ //\r
+ // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
+ // they can be RW. but can't be deleted. so they can always be found.\r
+ //\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_DEPLOYED_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &DeployedVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SETUP_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SetupVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SECURE_BOOT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SecureBootVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ //\r
+ // Make Secure Boot Mode transition ATOMIC\r
+ // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.\r
+ // other tranisition logic are all memory operations.\r
+ //\r
+ Status = UpdateSecureBootMode(NewMode);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
+ }\r
+\r
+ switch(NewMode) {\r
+ case SecureBootModeTypeUserMode:\r
+ //\r
+ // DeployedMode ----> UserMode\r
+ // Side Effects\r
+ // DeployedMode := 0\r
+ //\r
+ // Platform Specific DeployedMode clear. UpdateSecureBootMode fails and no other variables are updated before. rollback this transition\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
+\r
+ break;\r
+\r
+ case SecureBootModeTypeSetupMode:\r
+ //\r
+ // Since PK is processed before, can't rollback, still update SecureBootMode in memory\r
+ //\r
+ mSecureBootMode = NewMode;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // DeployedMode ----> SetupMode\r
+ //\r
+ // Platform Specific PKpub clear or Delete Pkpub\r
+ // Side Effects\r
+ // DeployedMode := 0 / SetupMode := 1 / SecureBoot := 0\r
+ //\r
+ // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
+ //\r
+ // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
+\r
+ if (mAuthVarLibContextIn->AtRuntime ()) {\r
+ //\r
+ // SecureBoot Variable indicates whether the platform firmware is operating\r
+ // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
+ // Variable in runtime.\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
+\r
+ //\r
+ // Delete the "SecureBootEnable" variable as secure boot is Disabled.\r
+ //\r
+ SecureBootEnable = SECURE_BOOT_DISABLE;\r
+ AuthServiceInternalUpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ 0,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ break;\r
+\r
+ default:\r
+ DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeDeployedMode, NewMode));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Current secure boot mode is UserMode. This function performs secure boot mode transition\r
+ to a new mode.\r
+\r
+ @param[in] NewMode New Secure Boot Mode.\r
+\r
+ @retval EFI_SUCCESS The initialization operation is successful.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+TransitionFromUserMode(\r
+ IN SECURE_BOOT_MODE_TYPE NewMode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *AuditVarData;\r
+ UINT8 *DeployedVarData;\r
+ UINT8 *SetupVarData;\r
+ UINT8 *PkVarData;\r
+ UINT8 *SecureBootVarData;\r
+ UINT8 SecureBootEnable;\r
+ UINTN DataSize;\r
+ VARIABLE_ENTRY_CONSISTENCY VariableEntry;\r
+\r
+ //\r
+ // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
+ // they can be RW. but can't be deleted. so they can always be found.\r
+ //\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_AUDIT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &AuditVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_DEPLOYED_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &DeployedVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SETUP_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SetupVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SECURE_BOOT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SecureBootVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ //\r
+ // Make Secure Boot Mode transition ATOMIC\r
+ // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow. \r
+ // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.\r
+ //\r
+ if (NewMode != SecureBootModeTypeAuditMode) {\r
+ Status = UpdateSecureBootMode(NewMode);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
+ }\r
+ } else {\r
+ //\r
+ // UserMode -----> AuditMode. Check RemainingSpace for SecureBootMode var first.\r
+ // Will update SecureBootMode after DeletePK logic\r
+ //\r
+ VariableEntry.VariableSize = sizeof(UINT8);\r
+ VariableEntry.Guid = &gEdkiiSecureBootModeGuid;\r
+ VariableEntry.Name = EDKII_SECURE_BOOT_MODE_NAME;\r
+ if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry, NULL)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ switch(NewMode) {\r
+ case SecureBootModeTypeDeployedMode:\r
+ //\r
+ // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // UserMode ----> DeployedMode\r
+ // Side Effects\r
+ // DeployedMode := 1\r
+ //\r
+ CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
+ break;\r
+\r
+ case SecureBootModeTypeAuditMode:\r
+ //\r
+ // UserMode ----> AuditMode\r
+ // Side Effects\r
+ // Delete PKpub / SetupMode := 1 / SecureBoot := 0\r
+ //\r
+ // Delete PKpub without verification. Should always succeed.\r
+ //\r
+ PkVarData = NULL;\r
+ Status = AuthServiceInternalUpdateVariable (\r
+ EFI_PLATFORM_KEY_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ PkVarData,\r
+ 0,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "UserMode -> AuditMode. Delete PK fail %x\n", Status));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ //\r
+ // Update Private NV SecureBootMode Variable\r
+ //\r
+ Status = UpdateSecureBootMode(NewMode);\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Since PK is deleted successfully, Doesn't break, continue to update other variable.\r
+ //\r
+ DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
+ }\r
+ CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));\r
+\r
+ //\r
+ // Fall into SetupMode logic\r
+ //\r
+ case SecureBootModeTypeSetupMode:\r
+ //\r
+ // Since PK is deleted before , can't rollback, still update SecureBootMode in memory\r
+ //\r
+ mSecureBootMode = NewMode;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // UserMode ----> SetupMode\r
+ // Side Effects\r
+ // DeployedMode :=0 / SetupMode :=1 / SecureBoot :=0\r
+ //\r
+ // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
+\r
+ if (mAuthVarLibContextIn->AtRuntime ()) {\r
+ //\r
+ // SecureBoot Variable indicates whether the platform firmware is operating\r
+ // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
+ // Variable in runtime.\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
+\r
+ //\r
+ // Delete the "SecureBootEnable" variable as secure boot is Disabled.\r
+ //\r
+ SecureBootEnable = SECURE_BOOT_DISABLE;\r
+ AuthServiceInternalUpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ 0,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+\r
+ break;\r
+\r
+ default:\r
+ DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeUserMode, NewMode));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Current secure boot mode is SetupMode. This function performs secure boot mode transition\r
+ to a new mode.\r
+\r
+ @param[in] NewMode New Secure Boot Mode.\r
+\r
+ @retval EFI_SUCCESS The initialization operation is successful.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+TransitionFromSetupMode(\r
+ IN SECURE_BOOT_MODE_TYPE NewMode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *AuditVarData;\r
+ UINT8 *SetupVarData;\r
+ UINT8 *SecureBootVarData;\r
+ UINT8 SecureBootEnable;\r
+ UINTN DataSize;\r
+\r
+ //\r
+ // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
+ // they can be RW. but can't be deleted. so they can always be found.\r
+ //\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_AUDIT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &AuditVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SETUP_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SetupVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Status = AuthServiceInternalFindVariable (\r
+ EFI_SECURE_BOOT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SecureBootVarData,\r
+ &DataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ //\r
+ // Make Secure Boot Mode transition ATOMIC\r
+ // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.\r
+ // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.\r
+ //\r
+ Status = UpdateSecureBootMode(NewMode);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
+ }\r
+\r
+ switch(NewMode) {\r
+ case SecureBootModeTypeAuditMode:\r
+ //\r
+ // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // SetupMode ----> AuditMode\r
+ // Side Effects\r
+ // AuditMode := 1\r
+ //\r
+ // Update the value of AuditMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));\r
+ break;\r
+\r
+ case SecureBootModeTypeUserMode:\r
+ //\r
+ // Since PK is enrolled before, can't rollback, still update SecureBootMode in memory\r
+ //\r
+ mSecureBootMode = NewMode;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // SetupMode ----> UserMode\r
+ // Side Effects\r
+ // SetupMode := 0 / SecureBoot := 1\r
+ //\r
+ // Update the value of AuditMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
+\r
+ if (mAuthVarLibContextIn->AtRuntime ()) {\r
+ //\r
+ // SecureBoot Variable indicates whether the platform firmware is operating\r
+ // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
+ // Variable in runtime.\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
+\r
+ //\r
+ // Create the "SecureBootEnable" variable as secure boot is enabled.\r
+ //\r
+ SecureBootEnable = SECURE_BOOT_ENABLE;\r
+ AuthServiceInternalUpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ sizeof (SecureBootEnable),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ break;\r
+\r
+ default:\r
+ DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeSetupMode, NewMode));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function performs main secure boot mode transition logic.\r
+\r
+ @param[in] CurMode Current Secure Boot Mode.\r
+ @param[in] NewMode New Secure Boot Mode.\r