swtpm: Track last command processed by the TPM

Track the last command processed by the TPM so we can determine whether
we may need to send a TPM2_Shutdown() before reset of the TPM 2.

Introduce a variable lastCommand to help track the last command that
was sent to the TPM 2.

In relation to deciding whether a TPM2_Shutdown() needs to be sent, the
tracking of the last-sent command is merely an optimization since for
example a VM with EDK2 will send a TPM2_Shutdown() followed by a
TPM2_GetRandom() upon suspend-to-ram, thus indicating that the last
command was TPM2_GetRandom(). However, under most circumstances it helps
to avoid sending an additional TPM2_Shutdown() if the OS TPM driver sent
one already.

When the suspended VM resume swtpm gets a CMD_INIT that requires swtpm
to decide whether a TPM2_Shutdown() needs to be sent and per the last-sent
command it will then send a TPM2_Shutdown(SU_STATE) as in the abrupt
termination case.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2022-05-30 10:40:01 -04:00 committed by Stefan Berger
parent 132f51d41b
commit 75fbda26f6
7 changed files with 41 additions and 1 deletions

View File

@ -110,6 +110,9 @@ static uint32_t locality_flags;
/* the fuse_session that we will signal an exit to to exit the prg. */
static struct fuse_session *ptm_fuse_session;
/* last command sent to the TPM */
static uint32_t g_lastCommand = TPM_ORDINAL_NONE;
#if GLIB_MAJOR_VERSION >= 2
# if GLIB_MINOR_VERSION >= 32
@ -518,6 +521,8 @@ static int ptm_send_startup(uint16_t startupType,
tpmversion,
command, max_command_length);
if (command_length > 0) {
g_lastCommand = tpmlib_get_cmd_ordinal(command, command_length);
rc = TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
(unsigned char *)command, command_length);
ptm_read_offset = 0;
@ -871,6 +876,8 @@ static void ptm_write_stateblob(fuse_req_t req, const char *buf, size_t size)
static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
TPMLIB_TPMVersion l_tpmversion)
{
uint32_t lastCommand;
ptm_req_len = size;
ptm_res_len = 0;
@ -896,6 +903,10 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
goto skip_process;
}
lastCommand = tpmlib_get_cmd_ordinal((unsigned char *)buf, ptm_req_len);
if (lastCommand != TPM_ORDINAL_NONE)
g_lastCommand = lastCommand;
if (tpmlib_is_request_cancelable(l_tpmversion,
(const unsigned char*)buf,
ptm_req_len)) {

View File

@ -102,6 +102,7 @@ int mainLoop(struct mainLoopParams *mlp,
struct iovec iov[3];
uint32_t ack = htobe32(0);
struct tpm2_resp_prefix respprefix;
uint32_t lastCommand;
/* poolfd[] indexes */
enum {
@ -141,9 +142,11 @@ int mainLoop(struct mainLoopParams *mlp,
mlp->startupType,
mlp->tpmversion,
command, max_command_length);
if (command_length > 0)
if (command_length > 0) {
mlp->lastCommand = tpmlib_get_cmd_ordinal(command, command_length);
rc = TPMLIB_Process(&rbuffer, &rlength, &rTotal,
command, command_length);
}
if (rc || command_length == 0) {
mainloop_terminate = true;
@ -273,6 +276,14 @@ int mainLoop(struct mainLoopParams *mlp,
}
}
if (rc == 0) {
lastCommand =
tpmlib_get_cmd_ordinal(&command[cmd_offset],
command_length - cmd_offset);
if (lastCommand != TPM_ORDINAL_NONE)
mlp->lastCommand = lastCommand;
}
if (rc == 0) {
rlength = 0; /* clear the response buffer */
rc = tpmlib_process(&rbuffer,

View File

@ -60,6 +60,7 @@ struct mainLoopParams {
uint32_t locality_flags;
TPMLIB_TPMVersion tpmversion;
uint16_t startupType; /* use TPM 1.2 types */
uint32_t lastCommand; /* last Command sent to TPM */
};
int mainLoop(struct mainLoopParams *mlp,

View File

@ -215,6 +215,7 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
.locality_flags = 0,
.tpmversion = TPMLIB_TPM_VERSION_1_2,
.startupType = _TPM_ST_NONE,
.lastCommand = TPM_ORDINAL_NONE,
};
struct server *server = NULL;
unsigned long val;

View File

@ -274,6 +274,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i
.locality_flags = 0,
.tpmversion = TPMLIB_TPM_VERSION_1_2,
.startupType = _TPM_ST_NONE,
.lastCommand = TPM_ORDINAL_NONE,
};
unsigned long val;
char *end_ptr;

View File

@ -155,6 +155,17 @@ int tpmlib_get_tpm_property(enum TPMLIB_TPMProperty prop)
return result;
}
uint32_t tpmlib_get_cmd_ordinal(const unsigned char *request, size_t req_len)
{
struct tpm_req_header *hdr;
if (req_len < sizeof(struct tpm_req_header))
return TPM_ORDINAL_NONE;
hdr = (struct tpm_req_header *)request;
return be32toh(hdr->ordinal);
}
bool tpmlib_is_request_cancelable(TPMLIB_TPMVersion tpmversion,
const unsigned char *request, size_t req_len)
{

View File

@ -49,6 +49,7 @@ TPM_RESULT tpmlib_register_callbacks(struct libtpms_callbacks *cbs);
TPM_RESULT tpmlib_choose_tpm_version(TPMLIB_TPMVersion tpmversion);
TPM_RESULT tpmlib_start(uint32_t flags, TPMLIB_TPMVersion tpmversion);
int tpmlib_get_tpm_property(enum TPMLIB_TPMProperty prop);
uint32_t tpmlib_get_cmd_ordinal(const unsigned char *request, size_t req_len);
bool tpmlib_is_request_cancelable(TPMLIB_TPMVersion tpmversion,
const unsigned char *request, size_t req_len);
void tpmlib_write_fatal_error_response(unsigned char **rbuffer,
@ -142,4 +143,7 @@ struct tpm_startup {
#define TPM2_SU_CLEAR 0x0000
#define TPM2_SU_STATE 0x0001
/* common */
#define TPM_ORDINAL_NONE 0x00000000
#endif /* _SWTPM_TPMLIB_H_ */