Commit 0c2f2309cd for qemu.org
commit 0c2f2309cddf6dcb5a340e7838e2b37e3fc22bf8
Author: Stefan Berger <stefanb@linux.vnet.ibm.com>
Date: Fri Oct 2 10:25:16 2026 -0400
tests: Add tests with commands with bad length
Add two test cases with commands with bad length:
- Send a command that indicates a very large size (0x10000 bytes) to the
TPM. This will only work with the CRB interface since the TIS wants
to receive all the bytes indicated by the command header.
- Send a command that indicates that its size is only 9 bytes, which is
too short to be valid since the command header alone is 10 bytes.
This test only works with the TIS. The CRB silently rejects commands
that are shorter than the command header.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20261002142516.2063735-11-stefanb@linux.ibm.com
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
diff --git a/tests/qtest/tpm-crb-swtpm-test.c b/tests/qtest/tpm-crb-swtpm-test.c
index 050c7b0c1f..0e83a5325f 100644
--- a/tests/qtest/tpm-crb-swtpm-test.c
+++ b/tests/qtest/tpm-crb-swtpm-test.c
@@ -33,6 +33,14 @@ static void tpm_crb_swtpm_test(const void *data)
"tpm-crb", NULL);
}
+static void tpm_crb_short_write_swtpm_test(const void *data)
+{
+ const TestState *ts = data;
+
+ tpm_test_short_write_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer,
+ "tpm-crb", NULL);
+}
+
static void tpm_crb_chunk_swtpm_test(const void *data)
{
const TestState *ts = data;
@@ -62,6 +70,8 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_data_func("/tpm/crb-swtpm/test", &ts, tpm_crb_swtpm_test);
+ qtest_add_data_func("/tpm/crb-short-write-swtpm/test", &ts,
+ tpm_crb_short_write_swtpm_test);
qtest_add_data_func("/tpm/crb-chunk-swtpm/test", &ts,
tpm_crb_chunk_swtpm_test);
qtest_add_data_func("/tpm/crb-swtpm-migration/test", &ts,
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index 1b4f932b0c..74b22c43aa 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -79,6 +79,62 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
qapi_free_SocketAddress(addr);
}
+/* Setup the TPM and send a command by calling a passed function */
+static void
+tpm_test_simple_cmd_swtpm_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options,
+ void (*test_func)(QTestState *, tx_func))
+{
+ char *args = NULL;
+ QTestState *s;
+ SocketAddress *addr = NULL;
+ gboolean succ;
+ GPid swtpm_pid;
+ GError *error = NULL;
+
+ if (tpm_test_swtpm_skip()) {
+ return;
+ }
+
+ succ = tpm_util_swtpm_start(src_tpm_path, &swtpm_pid, &addr, &error);
+ g_assert_true(succ);
+
+ args = g_strdup_printf(
+ "%s "
+ "-chardev socket,id=chr,path=%s "
+ "-tpmdev emulator,id=tpm0,chardev=chr "
+ "-device %s,tpmdev=tpm0",
+ machine_options ? : "", addr->u.q_unix.path, ifmodel);
+
+ s = qtest_start(args);
+ g_free(args);
+
+ test_func(s, tx);
+
+ qtest_end();
+ tpm_util_swtpm_kill(swtpm_pid);
+
+ g_unlink(addr->u.q_unix.path);
+ qapi_free_SocketAddress(addr);
+}
+
+void tpm_test_short_write_swtpm_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options)
+{
+ tpm_test_simple_cmd_swtpm_test(src_tpm_path, tx, ifmodel, machine_options,
+ tpm_util_short_write);
+}
+
+void tpm_test_too_short_cmd_swtpm_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options)
+{
+ tpm_test_simple_cmd_swtpm_test(src_tpm_path, tx, ifmodel, machine_options,
+ tpm_util_too_short_cmd);
+}
+
void tpm_test_swtpm_migration_test(const char *src_tpm_path,
const char *dst_tpm_path,
const char *uri, tx_func *tx,
diff --git a/tests/qtest/tpm-tests.h b/tests/qtest/tpm-tests.h
index 07ba60d26e..7684abf8f4 100644
--- a/tests/qtest/tpm-tests.h
+++ b/tests/qtest/tpm-tests.h
@@ -18,6 +18,14 @@
void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
const char *ifmodel, const char *machine_options);
+void tpm_test_short_write_swtpm_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options);
+
+void tpm_test_too_short_cmd_swtpm_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options);
+
void tpm_test_swtpm_migration_test(const char *src_tpm_path,
const char *dst_tpm_path,
const char *uri, tx_func *tx,
diff --git a/tests/qtest/tpm-tis-device-swtpm-test.c b/tests/qtest/tpm-tis-device-swtpm-test.c
index 517a077005..48a7389306 100644
--- a/tests/qtest/tpm-tis-device-swtpm-test.c
+++ b/tests/qtest/tpm-tis-device-swtpm-test.c
@@ -38,6 +38,14 @@ static void tpm_tis_swtpm_test(const void *data)
"tpm-tis-device", MACHINE_OPTIONS);
}
+static void tpm_tis_too_short_cmd_swtpm_test(const void *data)
+{
+ const TestState *ts = data;
+
+ tpm_test_too_short_cmd_swtpm_test(ts->src_tpm_path, tpm_tis_transfer,
+ "tpm-tis-device", MACHINE_OPTIONS);
+}
+
static void tpm_tis_swtpm_migration_test(const void *data)
{
const TestState *ts = data;
@@ -62,6 +70,8 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test);
+ qtest_add_data_func("/tpm/tis-too-short-cmd-swtpm/test", &ts,
+ tpm_tis_too_short_cmd_swtpm_test);
qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts,
tpm_tis_swtpm_migration_test);
ret = g_test_run();
diff --git a/tests/qtest/tpm-tis-swtpm-test.c b/tests/qtest/tpm-tis-swtpm-test.c
index 105e42e21d..14b4cbce21 100644
--- a/tests/qtest/tpm-tis-swtpm-test.c
+++ b/tests/qtest/tpm-tis-swtpm-test.c
@@ -36,6 +36,14 @@ static void tpm_tis_swtpm_test(const void *data)
"tpm-tis", NULL);
}
+static void tpm_tis_too_short_cmd_swtpm_test(const void *data)
+{
+ const TestState *ts = data;
+
+ tpm_test_too_short_cmd_swtpm_test(ts->src_tpm_path, tpm_tis_transfer,
+ "tpm-tis", NULL);
+}
+
static void tpm_tis_swtpm_migration_test(const void *data)
{
const TestState *ts = data;
@@ -57,6 +65,8 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test);
+ qtest_add_data_func("/tpm/tis-too-short-cmd-swtpm/test", &ts,
+ tpm_tis_too_short_cmd_swtpm_test);
qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts,
tpm_tis_swtpm_migration_test);
ret = g_test_run();
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index 151002ea24..d2042ed5df 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -194,6 +194,61 @@ void tpm_util_pcrread(QTestState *s, tx_func *tx,
&exp_resp[14], exp_resp_size - 14);
}
+/*
+ * Write a TPM command with too large length indicator
+ * The CRB will send the command to the TPM.
+ * The TIS will never send the command since it wants to receive the number of
+ * bytes indicate in the command.
+ */
+void tpm_util_short_write(QTestState *s, tx_func *tx)
+{
+ unsigned char buffer[1024] = { 0 };
+ static const unsigned char tpm_bad_command[] = {
+ 0x80, 0x01,
+ 0x00, 0x01, 0x00, 0x00, /* length = 0x10000 */
+ 0x00, 0x00, 0x01, 0x7e,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x03, 0x00, 0x04, 0x00
+ };
+
+ tx(s, tpm_bad_command, sizeof(tpm_bad_command), buffer, sizeof(buffer));
+
+ static const unsigned char tpm_error_resp[] = {
+ 0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x01, 0x42, /* TPM_RC_COMMAND_SIZE */
+ };
+
+ g_assert_cmpmem(buffer, sizeof(tpm_error_resp),
+ tpm_error_resp, sizeof(tpm_error_resp));
+}
+
+/*
+ * Write a TPM command that is shorter than the header.
+ * The CRB will not send this command.
+ * The TIS will send the command to the backend (needs to be at least
+ * 6 bytes).
+ */
+void tpm_util_too_short_cmd(QTestState *s, tx_func *tx)
+{
+ unsigned char buffer[1024] = { 0 };
+ static const unsigned char tpm_bad_command[] = {
+ 0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x09, /* 9 bytes command is too short */
+ 0x00, 0x00, 0x01,
+ };
+
+ tx(s, tpm_bad_command, sizeof(tpm_bad_command), buffer, sizeof(buffer));
+
+ static const unsigned char tpm_error_resp[] = {
+ 0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x01, 0x01, /* TPM_RC_FAILURE from tpm_emulator.c */
+ };
+
+ g_assert_cmpmem(buffer, sizeof(tpm_error_resp),
+ tpm_error_resp, sizeof(tpm_error_resp));
+}
+
bool tpm_util_swtpm_has_tpm2(void)
{
bool has_tpm2 = false;
diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h
index 681544e7d8..70c2fc09c6 100644
--- a/tests/qtest/tpm-util.h
+++ b/tests/qtest/tpm-util.h
@@ -38,6 +38,9 @@ void tpm_util_pcrextend(QTestState *s, tx_func *tx);
void tpm_util_pcrread(QTestState *s, tx_func *tx,
const unsigned char *exp_resp, size_t exp_resp_size);
+void tpm_util_short_write(QTestState *s, tx_func *tx);
+void tpm_util_too_short_cmd(QTestState *s, tx_func *tx);
+
bool tpm_util_swtpm_has_tpm2(void);
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,