Skip to content

Commit bbf20d8

Browse files
committed
Fix Tcg2SubmitCommand in TPM field upgrade scenario.
There's a bug that after the device was forced shut down during the tpm firmware update process, then the TPM will stay in field upgrade mode and refuse to work properly. This will block TPM startup and cause the device to bootloop. Now in the TCG_DXE_DATA struct we don’t have a flag to indicate the current TPM mode, and we will simply treat the upper Scenario with this DEVICE_ERROR and set the TPMPresentFlag to FALSE. Later in Tcg2SubmitCommand we will just return DEVICE_ERROR and skip the actual TPM recovery. We should have an extra flag that check for the TPM response code and if it's TPM_RC_UPGRADE, we knew the device is in field upgrade mode and should continue the workflow. We should only return EFI_DEVICE_ERROR when both TPMPresentFlag and TpmUpdateFlag are false. The field upgrade is part of TCG spec, and the capsule update/recovery is part of UEFI spec. Make this PR to bring in the fix for this corner case. Signed-off-by: Liqi Qi <[email protected]>
1 parent 49d4753 commit bbf20d8

File tree

1 file changed

+51
-11
lines changed

1 file changed

+51
-11
lines changed

SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ typedef struct {
8181

8282
typedef struct _TCG_DXE_DATA {
8383
EFI_TCG2_BOOT_SERVICE_CAPABILITY BsCap;
84+
BOOLEAN TpmUpdateFlag;
8485
TCG_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX];
8586
BOOLEAN GetEventLogCalled[TCG_EVENT_LOG_AREA_COUNT_MAX];
8687
TCG_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX];
@@ -101,6 +102,7 @@ TCG_DXE_DATA mTcgDxeData = {
101102
0, // NumberOfPCRBanks
102103
0, // ActivePcrBanks
103104
},
105+
FALSE,
104106
};
105107

106108
UINTN mBootAttempts = 0;
@@ -1407,6 +1409,8 @@ Tcg2SubmitCommand (
14071409
)
14081410
{
14091411
EFI_STATUS Status;
1412+
TPM_RC ResponseCode;
1413+
UINT32 CurrentOutputBlockSize;
14101414

14111415
if ((This == NULL) ||
14121416
(InputParameterBlockSize == 0) || (InputParameterBlock == NULL) ||
@@ -1415,10 +1419,6 @@ Tcg2SubmitCommand (
14151419
return EFI_INVALID_PARAMETER;
14161420
}
14171421

1418-
if (!mTcgDxeData.BsCap.TPMPresentFlag) {
1419-
return EFI_DEVICE_ERROR;
1420-
}
1421-
14221422
if (InputParameterBlockSize > mTcgDxeData.BsCap.MaxCommandSize) {
14231423
return EFI_INVALID_PARAMETER;
14241424
}
@@ -1427,13 +1427,53 @@ Tcg2SubmitCommand (
14271427
return EFI_INVALID_PARAMETER;
14281428
}
14291429

1430-
Status = Tpm2SubmitCommand (
1431-
InputParameterBlockSize,
1432-
InputParameterBlock,
1433-
&OutputParameterBlockSize,
1434-
OutputParameterBlock
1435-
);
1436-
return Status;
1430+
//
1431+
// Always attempt to submit the command, but if the TPM is already flagged
1432+
// as not present, we expect it to fail other than the capsule update scenario.
1433+
//
1434+
CurrentOutputBlockSize = OutputParameterBlockSize;
1435+
Status = Tpm2SubmitCommand (
1436+
InputParameterBlockSize,
1437+
InputParameterBlock,
1438+
&CurrentOutputBlockSize,
1439+
OutputParameterBlock
1440+
);
1441+
if (EFI_ERROR (Status)) {
1442+
return mTcgDxeData.BsCap.TPMPresentFlag ? Status : EFI_DEVICE_ERROR;
1443+
}
1444+
1445+
if (CurrentOutputBlockSize < sizeof (TPM2_RESPONSE_HEADER)) {
1446+
DEBUG ((DEBUG_ERROR, "%a: Response buffer too small!\n", __func__));
1447+
return EFI_DEVICE_ERROR;
1448+
}
1449+
1450+
//
1451+
// Correctly read the response code and swap bytes from Big-Endian to Host order.
1452+
// The responseCode field is at offset 6 of the response header.
1453+
//
1454+
ResponseCode = SwapBytes32 (ReadUnaligned32 ((UINT32 *)(OutputParameterBlock + 6)));
1455+
DEBUG ((DEBUG_ERROR, "Response code is %x", ResponseCode));
1456+
// If the response code ever equals to TPM_RC_UPGRADE, it means the TPM is in field
1457+
// upgrade mode, we set both flags to TRUE.
1458+
if (ResponseCode == TPM_RC_UPGRADE) {
1459+
DEBUG ((DEBUG_INFO, "TPM response code TPM_RC_UPDATE received. Setting flag.\n"));
1460+
mTcgDxeData.TpmUpdateFlag = TRUE;
1461+
mTcgDxeData.BsCap.TPMPresentFlag = TRUE;
1462+
}
1463+
1464+
// Now that we have set the TPMPresentFlag, it should be able to reflect the actual TPM presence.
1465+
if (!mTcgDxeData.BsCap.TPMPresentFlag) {
1466+
DEBUG ((DEBUG_WARN, "%a: TPMPresentFlag is FALSE. Expecting command to fail.\n", __func__));
1467+
return EFI_DEVICE_ERROR;
1468+
}
1469+
1470+
// If the response code is not TPM_RC_SUCCESS and the device is not in field update mode, return error.
1471+
if ((ResponseCode != TPM_RC_SUCCESS) && (mTcgDxeData.TpmUpdateFlag == FALSE)) {
1472+
DEBUG ((DEBUG_ERROR, "%a: Command failed with response code 0x%x\n", __func__, ResponseCode));
1473+
return EFI_DEVICE_ERROR;
1474+
}
1475+
1476+
return EFI_SUCCESS;
14371477
}
14381478

14391479
/**

0 commit comments

Comments
 (0)