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>
diff --git a/src/swtpm/cuse_tpm.c b/src/swtpm/cuse_tpm.c
index e73b413..dcbe018 100644
--- a/src/swtpm/cuse_tpm.c
+++ b/src/swtpm/cuse_tpm.c
@@ -110,6 +110,9 @@
/* 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 @@
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_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 @@
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)) {
diff --git a/src/swtpm/mainloop.c b/src/swtpm/mainloop.c
index 44d67b7..5280f90 100644
--- a/src/swtpm/mainloop.c
+++ b/src/swtpm/mainloop.c
@@ -102,6 +102,7 @@
struct iovec iov[3];
uint32_t ack = htobe32(0);
struct tpm2_resp_prefix respprefix;
+ uint32_t lastCommand;
/* poolfd[] indexes */
enum {
@@ -141,9 +142,11 @@
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;
@@ -274,6 +277,14 @@
}
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,
&rlength,
diff --git a/src/swtpm/mainloop.h b/src/swtpm/mainloop.h
index c006d14..8feed1e 100644
--- a/src/swtpm/mainloop.h
+++ b/src/swtpm/mainloop.h
@@ -60,6 +60,7 @@
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,
diff --git a/src/swtpm/swtpm.c b/src/swtpm/swtpm.c
index b8bf8d9..c2c255b 100644
--- a/src/swtpm/swtpm.c
+++ b/src/swtpm/swtpm.c
@@ -215,6 +215,7 @@
.locality_flags = 0,
.tpmversion = TPMLIB_TPM_VERSION_1_2,
.startupType = _TPM_ST_NONE,
+ .lastCommand = TPM_ORDINAL_NONE,
};
struct server *server = NULL;
unsigned long val;
diff --git a/src/swtpm/swtpm_chardev.c b/src/swtpm/swtpm_chardev.c
index 6c9ef13..a1d6c8d 100644
--- a/src/swtpm/swtpm_chardev.c
+++ b/src/swtpm/swtpm_chardev.c
@@ -274,6 +274,7 @@
.locality_flags = 0,
.tpmversion = TPMLIB_TPM_VERSION_1_2,
.startupType = _TPM_ST_NONE,
+ .lastCommand = TPM_ORDINAL_NONE,
};
unsigned long val;
char *end_ptr;
diff --git a/src/swtpm/tpmlib.c b/src/swtpm/tpmlib.c
index 4771995..b29a3d0 100644
--- a/src/swtpm/tpmlib.c
+++ b/src/swtpm/tpmlib.c
@@ -155,6 +155,17 @@
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)
{
diff --git a/src/swtpm/tpmlib.h b/src/swtpm/tpmlib.h
index 16ab717..2f018cf 100644
--- a/src/swtpm/tpmlib.h
+++ b/src/swtpm/tpmlib.h
@@ -49,6 +49,7 @@
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 @@
#define TPM2_SU_CLEAR 0x0000
#define TPM2_SU_STATE 0x0001
+/* common */
+#define TPM_ORDINAL_NONE 0x00000000
+
#endif /* _SWTPM_TPMLIB_H_ */