mirror of https://github.com/acidanthera/audk.git
SecurityPkg: Make time based AuthVariable update atomic
System may break during time based AuthVariable update, causing certdb inconsistent. 2 ways are used to ensure update atomic. 1. Delete cert in certdb after variable is deleted 2. Clean up certdb on variable initialization Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang <chao.b.zhang@intel.com> Reviewed-by: Yao Jiewen <jiewen.yao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17919 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
cfa451c84a
commit
64b6a3ff4a
|
@ -1205,18 +1205,17 @@ ProcessVariable (
|
|||
//
|
||||
// Allow the delete operation of common authenticated variable at user physical presence.
|
||||
//
|
||||
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
|
||||
Status = AuthServiceInternalUpdateVariable (
|
||||
VariableName,
|
||||
VendorGuid,
|
||||
NULL,
|
||||
0,
|
||||
0
|
||||
);
|
||||
if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
|
||||
Status = DeleteCertsFromDb (VariableName, VendorGuid);
|
||||
}
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = AuthServiceInternalUpdateVariable (
|
||||
VariableName,
|
||||
VendorGuid,
|
||||
NULL,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -1964,6 +1963,109 @@ InsertCertsToDb (
|
|||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Clean up signer's certificates for common authenticated variable
|
||||
by corresponding VariableName and VendorGuid from "certdb".
|
||||
Sytem may break down during Timebased Variable update & certdb update,
|
||||
make them inconsistent, this function is called in AuthVariable Init to ensure
|
||||
consistency
|
||||
|
||||
@retval EFI_NOT_FOUND Fail to find matching certs.
|
||||
@retval EFI_SUCCESS Find matching certs and output parameters.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
CleanCertsFromDb (
|
||||
VOID
|
||||
){
|
||||
UINT32 Offset;
|
||||
AUTH_CERT_DB_DATA *Ptr;
|
||||
UINT32 NameSize;
|
||||
UINT32 NodeSize;
|
||||
CHAR16 *VariableName;
|
||||
EFI_STATUS Status;
|
||||
BOOLEAN CertCleaned;
|
||||
UINT8 *Data;
|
||||
UINTN DataSize;
|
||||
UINT8 *AuthVarData;
|
||||
UINTN AuthVarDataSize;
|
||||
EFI_GUID AuthVarGuid;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
//
|
||||
// Get corresponding certificates by VendorGuid and VariableName.
|
||||
//
|
||||
do {
|
||||
CertCleaned = FALSE;
|
||||
|
||||
//
|
||||
// Get latest variable "certdb"
|
||||
//
|
||||
Status = AuthServiceInternalFindVariable (
|
||||
EFI_CERT_DB_NAME,
|
||||
&gEfiCertDbGuid,
|
||||
(VOID **) &Data,
|
||||
&DataSize
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if ((DataSize == 0) || (Data == NULL)) {
|
||||
ASSERT (FALSE);
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
Offset = sizeof (UINT32);
|
||||
|
||||
while (Offset < (UINT32) DataSize) {
|
||||
Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
|
||||
//
|
||||
// Check whether VendorGuid matches.
|
||||
//
|
||||
NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
|
||||
NameSize = ReadUnaligned32 (&Ptr->NameSize);
|
||||
|
||||
//
|
||||
// Get VarName tailed with '\0'
|
||||
//
|
||||
VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16));
|
||||
if (VariableName == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16));
|
||||
//
|
||||
// Keep VarGuid aligned
|
||||
//
|
||||
CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID));
|
||||
|
||||
//
|
||||
// Find corresponding time auth variable
|
||||
//
|
||||
Status = AuthServiceInternalFindVariable (
|
||||
VariableName,
|
||||
&AuthVarGuid,
|
||||
(VOID **) &AuthVarData,
|
||||
&AuthVarDataSize
|
||||
);
|
||||
|
||||
if (EFI_ERROR(Status)) {
|
||||
Status = DeleteCertsFromDb(VariableName, &AuthVarGuid);
|
||||
CertCleaned = TRUE;
|
||||
DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));
|
||||
FreePool(VariableName);
|
||||
break;
|
||||
}
|
||||
|
||||
FreePool(VariableName);
|
||||
Offset = Offset + NodeSize;
|
||||
}
|
||||
} while (CertCleaned);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
|
||||
|
||||
|
@ -2285,16 +2387,7 @@ VerifyTimeBasedPayload (
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Delete signer's certificates when delete the common authenticated variable.
|
||||
//
|
||||
if ((PayloadSize == 0) && (OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
|
||||
Status = DeleteCertsFromDb (VariableName, VendorGuid);
|
||||
if (EFI_ERROR (Status)) {
|
||||
VerifyStatus = FALSE;
|
||||
goto Exit;
|
||||
}
|
||||
} else if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
|
||||
if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
|
||||
//
|
||||
// Insert signer's certificates when adding a new common authenticated variable.
|
||||
//
|
||||
|
@ -2389,6 +2482,7 @@ VerifyTimeBasedPayloadAndUpdate (
|
|||
UINTN PayloadSize;
|
||||
EFI_VARIABLE_AUTHENTICATION_2 *CertData;
|
||||
AUTH_VARIABLE_INFO OrgVariableInfo;
|
||||
BOOLEAN IsDel;
|
||||
|
||||
ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
|
||||
FindStatus = mAuthVarLibContextIn->FindVariable (
|
||||
|
@ -2412,8 +2506,12 @@ VerifyTimeBasedPayloadAndUpdate (
|
|||
return Status;
|
||||
}
|
||||
|
||||
if ((PayloadSize == 0) && (VarDel != NULL)) {
|
||||
*VarDel = TRUE;
|
||||
if (!EFI_ERROR(FindStatus)
|
||||
&& (PayloadSize == 0)
|
||||
&& ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
|
||||
IsDel = TRUE;
|
||||
} else {
|
||||
IsDel = FALSE;
|
||||
}
|
||||
|
||||
CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
|
||||
|
@ -2421,12 +2519,29 @@ VerifyTimeBasedPayloadAndUpdate (
|
|||
//
|
||||
// Final step: Update/Append Variable if it pass Pkcs7Verify
|
||||
//
|
||||
return AuthServiceInternalUpdateVariableWithTimeStamp (
|
||||
VariableName,
|
||||
VendorGuid,
|
||||
PayloadPtr,
|
||||
PayloadSize,
|
||||
Attributes,
|
||||
&CertData->TimeStamp
|
||||
);
|
||||
Status = AuthServiceInternalUpdateVariableWithTimeStamp (
|
||||
VariableName,
|
||||
VendorGuid,
|
||||
PayloadPtr,
|
||||
PayloadSize,
|
||||
Attributes,
|
||||
&CertData->TimeStamp
|
||||
);
|
||||
|
||||
//
|
||||
// Delete signer's certificates when delete the common authenticated variable.
|
||||
//
|
||||
if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) {
|
||||
Status = DeleteCertsFromDb (VariableName, VendorGuid);
|
||||
}
|
||||
|
||||
if (VarDel != NULL) {
|
||||
if (IsDel && !EFI_ERROR(Status)) {
|
||||
*VarDel = TRUE;
|
||||
} else {
|
||||
*VarDel = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
|
|
@ -186,6 +186,22 @@ DeleteCertsFromDb (
|
|||
IN EFI_GUID *VendorGuid
|
||||
);
|
||||
|
||||
/**
|
||||
Clean up signer's certificates for common authenticated variable
|
||||
by corresponding VariableName and VendorGuid from "certdb".
|
||||
Sytem may break down during Timebased Variable update & certdb update,
|
||||
make them inconsistent, this function is called in AuthVariable Init to ensure
|
||||
consistency
|
||||
|
||||
@retval EFI_NOT_FOUND Fail to find matching certs.
|
||||
@retval EFI_SUCCESS Find matching certs and output parameters.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
CleanCertsFromDb (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
|
||||
|
||||
|
|
|
@ -352,6 +352,15 @@ AuthVariableLibInitialize (
|
|||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Clean up Certs to make certDB & Time based auth variable consistent
|
||||
//
|
||||
Status = CleanCertsFromDb();
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_INFO, "Clean up CertDB fail! Status %x\n", Status));
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue