]> git.proxmox.com Git - mirror_qemu.git/blob - tests/tpm-crb-swtpm-test.c
Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2018-05-23-4' into...
[mirror_qemu.git] / tests / tpm-crb-swtpm-test.c
1 /*
2 * QTest testcase for TPM CRB talking to external swtpm and swtpm migration
3 *
4 * Copyright (c) 2018 IBM Corporation
5 * with parts borrowed from migration-test.c that is:
6 * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
7 *
8 * Authors:
9 * Stefan Berger <stefanb@linux.vnet.ibm.com>
10 *
11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
12 * See the COPYING file in the top-level directory.
13 */
14
15 #include "qemu/osdep.h"
16 #include <glib/gstdio.h>
17
18 #include "hw/acpi/tpm.h"
19 #include "io/channel-socket.h"
20 #include "libqtest.h"
21 #include "tpm-util.h"
22 #include "sysemu/tpm.h"
23 #include "qapi/qmp/qdict.h"
24
25 typedef struct TestState {
26 char *src_tpm_path;
27 char *dst_tpm_path;
28 char *uri;
29 } TestState;
30
31 bool got_stop;
32
33 static void migrate(QTestState *who, const char *uri)
34 {
35 QDict *rsp;
36 gchar *cmd;
37
38 cmd = g_strdup_printf("{ 'execute': 'migrate',"
39 "'arguments': { 'uri': '%s' } }",
40 uri);
41 rsp = qtest_qmp(who, cmd);
42 g_free(cmd);
43 g_assert(qdict_haskey(rsp, "return"));
44 qobject_unref(rsp);
45 }
46
47 /*
48 * Events can get in the way of responses we are actually waiting for.
49 */
50 static QDict *wait_command(QTestState *who, const char *command)
51 {
52 const char *event_string;
53 QDict *response;
54
55 response = qtest_qmp(who, command);
56
57 while (qdict_haskey(response, "event")) {
58 /* OK, it was an event */
59 event_string = qdict_get_str(response, "event");
60 if (!strcmp(event_string, "STOP")) {
61 got_stop = true;
62 }
63 qobject_unref(response);
64 response = qtest_qmp_receive(who);
65 }
66 return response;
67 }
68
69 static void wait_for_migration_complete(QTestState *who)
70 {
71 while (true) {
72 QDict *rsp, *rsp_return;
73 bool completed;
74 const char *status;
75
76 rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
77 rsp_return = qdict_get_qdict(rsp, "return");
78 status = qdict_get_str(rsp_return, "status");
79 completed = strcmp(status, "completed") == 0;
80 g_assert_cmpstr(status, !=, "failed");
81 qobject_unref(rsp);
82 if (completed) {
83 return;
84 }
85 usleep(1000);
86 }
87 }
88
89 static void migration_start_qemu(QTestState **src_qemu, QTestState **dst_qemu,
90 SocketAddress *src_tpm_addr,
91 SocketAddress *dst_tpm_addr,
92 const char *miguri)
93 {
94 char *src_qemu_args, *dst_qemu_args;
95
96 src_qemu_args = g_strdup_printf(
97 "-chardev socket,id=chr,path=%s "
98 "-tpmdev emulator,id=dev,chardev=chr "
99 "-device tpm-crb,tpmdev=dev ",
100 src_tpm_addr->u.q_unix.path);
101
102 *src_qemu = qtest_init(src_qemu_args);
103
104 dst_qemu_args = g_strdup_printf(
105 "-chardev socket,id=chr,path=%s "
106 "-tpmdev emulator,id=dev,chardev=chr "
107 "-device tpm-crb,tpmdev=dev "
108 "-incoming %s",
109 dst_tpm_addr->u.q_unix.path,
110 miguri);
111
112 *dst_qemu = qtest_init(dst_qemu_args);
113
114 free(src_qemu_args);
115 free(dst_qemu_args);
116 }
117
118 static void tpm_crb_swtpm_test(const void *data)
119 {
120 char *args = NULL;
121 QTestState *s;
122 SocketAddress *addr = NULL;
123 gboolean succ;
124 GPid swtpm_pid;
125 GError *error = NULL;
126 const TestState *ts = data;
127
128 succ = tpm_util_swtpm_start(ts->src_tpm_path, &swtpm_pid, &addr, &error);
129 /* succ may be false if swtpm is not available */
130 if (!succ) {
131 return;
132 }
133
134 args = g_strdup_printf(
135 "-chardev socket,id=chr,path=%s "
136 "-tpmdev emulator,id=dev,chardev=chr "
137 "-device tpm-crb,tpmdev=dev",
138 addr->u.q_unix.path);
139
140 s = qtest_start(args);
141 g_free(args);
142
143 tpm_util_startup(s, tpm_util_crb_transfer);
144 tpm_util_pcrextend(s, tpm_util_crb_transfer);
145
146 unsigned char tpm_pcrread_resp[] =
147 "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
148 "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
149 "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
150 "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
151 tpm_util_pcrread(s, tpm_util_crb_transfer, tpm_pcrread_resp,
152 sizeof(tpm_pcrread_resp));
153
154 qtest_end();
155 tpm_util_swtpm_kill(swtpm_pid);
156
157 if (addr) {
158 g_unlink(addr->u.q_unix.path);
159 qapi_free_SocketAddress(addr);
160 }
161 }
162
163 static void tpm_crb_swtpm_migration_test(const void *data)
164 {
165 const TestState *ts = data;
166 gboolean succ;
167 GPid src_tpm_pid, dst_tpm_pid;
168 SocketAddress *src_tpm_addr = NULL, *dst_tpm_addr = NULL;
169 GError *error = NULL;
170 QTestState *src_qemu, *dst_qemu;
171
172 succ = tpm_util_swtpm_start(ts->src_tpm_path, &src_tpm_pid,
173 &src_tpm_addr, &error);
174 /* succ may be false if swtpm is not available */
175 if (!succ) {
176 return;
177 }
178
179 succ = tpm_util_swtpm_start(ts->dst_tpm_path, &dst_tpm_pid,
180 &dst_tpm_addr, &error);
181 /* succ may be false if swtpm is not available */
182 if (!succ) {
183 goto err_src_tpm_kill;
184 }
185
186 migration_start_qemu(&src_qemu, &dst_qemu, src_tpm_addr, dst_tpm_addr,
187 ts->uri);
188
189 tpm_util_startup(src_qemu, tpm_util_crb_transfer);
190 tpm_util_pcrextend(src_qemu, tpm_util_crb_transfer);
191
192 unsigned char tpm_pcrread_resp[] =
193 "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
194 "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
195 "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
196 "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
197 tpm_util_pcrread(src_qemu, tpm_util_crb_transfer, tpm_pcrread_resp,
198 sizeof(tpm_pcrread_resp));
199
200 migrate(src_qemu, ts->uri);
201 wait_for_migration_complete(src_qemu);
202
203 tpm_util_pcrread(dst_qemu, tpm_util_crb_transfer, tpm_pcrread_resp,
204 sizeof(tpm_pcrread_resp));
205
206 qtest_quit(dst_qemu);
207 qtest_quit(src_qemu);
208
209 tpm_util_swtpm_kill(dst_tpm_pid);
210 if (dst_tpm_addr) {
211 g_unlink(dst_tpm_addr->u.q_unix.path);
212 qapi_free_SocketAddress(dst_tpm_addr);
213 }
214
215 err_src_tpm_kill:
216 tpm_util_swtpm_kill(src_tpm_pid);
217 if (src_tpm_addr) {
218 g_unlink(src_tpm_addr->u.q_unix.path);
219 qapi_free_SocketAddress(src_tpm_addr);
220 }
221 }
222
223 int main(int argc, char **argv)
224 {
225 int ret;
226 TestState ts = { 0 };
227
228 ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
229 ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
230 ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
231
232 module_call_init(MODULE_INIT_QOM);
233 g_test_init(&argc, &argv, NULL);
234
235 qtest_add_data_func("/tpm/crb-swtpm/test", &ts, tpm_crb_swtpm_test);
236 qtest_add_data_func("/tpm/crb-swtpm-migration/test", &ts,
237 tpm_crb_swtpm_migration_test);
238 ret = g_test_run();
239
240 g_rmdir(ts.dst_tpm_path);
241 g_free(ts.dst_tpm_path);
242 g_rmdir(ts.src_tpm_path);
243 g_free(ts.src_tpm_path);
244 g_free(ts.uri);
245
246 return ret;
247 }