]> git.proxmox.com Git - mirror_qemu.git/blame - tests/tpm-util.c
test: Move reusable code from tpm-crb-swtpm-test.c to tpm-util.c
[mirror_qemu.git] / tests / tpm-util.c
CommitLineData
b21373d0
SB
1/*
2 * QTest TPM utilities
3 *
4 * Copyright (c) 2018 IBM Corporation
5 * Copyright (c) 2018 Red Hat, Inc.
6 *
7 * Authors:
8 * Stefan Berger <stefanb@linux.vnet.ibm.com>
9 * Marc-André Lureau <marcandre.lureau@redhat.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
17#include "hw/acpi/tpm.h"
18#include "libqtest.h"
19#include "tpm-util.h"
b1e4b7c6
SB
20#include "qapi/qmp/qdict.h"
21
22static bool got_stop;
b21373d0
SB
23
24void tpm_util_crb_transfer(QTestState *s,
25 const unsigned char *req, size_t req_size,
26 unsigned char *rsp, size_t rsp_size)
27{
28 uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
29 uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
30
31 qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
32
33 qtest_memwrite(s, caddr, req, req_size);
34
35 uint32_t sts, start = 1;
36 uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
37 qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
38 while (true) {
39 start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
40 if ((start & 1) == 0) {
41 break;
42 }
43 if (g_get_monotonic_time() >= end_time) {
44 break;
45 }
46 };
47 start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
48 g_assert_cmpint(start & 1, ==, 0);
49 sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
50 g_assert_cmpint(sts & 1, ==, 0);
51
52 qtest_memread(s, raddr, rsp, rsp_size);
53}
54
55void tpm_util_startup(QTestState *s, tx_func *tx)
56{
57 unsigned char buffer[1024];
58 unsigned char tpm_startup[] =
59 "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
60 unsigned char tpm_startup_resp[] =
61 "\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
62
63 tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
64
65 g_assert_cmpmem(buffer, sizeof(tpm_startup_resp),
66 tpm_startup_resp, sizeof(tpm_startup_resp));
67}
68
69void tpm_util_pcrextend(QTestState *s, tx_func *tx)
70{
71 unsigned char buffer[1024];
72 unsigned char tpm_pcrextend[] =
73 "\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
74 "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
75 "\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
76 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
77 "\x00";
78
79 unsigned char tpm_pcrextend_resp[] =
80 "\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
81 "\x01\x00\x00";
82
83 tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
84
85 g_assert_cmpmem(buffer, sizeof(tpm_pcrextend_resp),
86 tpm_pcrextend_resp, sizeof(tpm_pcrextend_resp));
87}
88
89void tpm_util_pcrread(QTestState *s, tx_func *tx,
90 const unsigned char *exp_resp, size_t exp_resp_size)
91{
92 unsigned char buffer[1024];
93 unsigned char tpm_pcrread[] =
94 "\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
95 "\x03\x00\x04\x00";
96
97 tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
98
99 g_assert_cmpmem(buffer, exp_resp_size, exp_resp, exp_resp_size);
100}
101
102static gboolean tpm_util_swtpm_has_tpm2(void)
103{
104 gint mystdout;
105 gboolean succ;
106 unsigned i;
107 char buffer[10240];
108 ssize_t n;
109 gchar *swtpm_argv[] = {
110 g_strdup("swtpm"), g_strdup("socket"), g_strdup("--help"), NULL
111 };
112
113 succ = g_spawn_async_with_pipes(NULL, swtpm_argv, NULL,
114 G_SPAWN_SEARCH_PATH, NULL, NULL, NULL,
115 NULL, &mystdout, NULL, NULL);
116 if (!succ) {
117 goto cleanup;
118 }
119
120 n = read(mystdout, buffer, sizeof(buffer) - 1);
121 if (n < 0) {
122 goto cleanup;
123 }
124 buffer[n] = 0;
125 if (!strstr(buffer, "--tpm2")) {
126 succ = false;
127 }
128
129 cleanup:
130 for (i = 0; swtpm_argv[i]; i++) {
131 g_free(swtpm_argv[i]);
132 }
133
134 return succ;
135}
136
137gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
138 SocketAddress **addr, GError **error)
139{
140 char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
141 char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
142 path);
143 gchar *swtpm_argv[] = {
144 g_strdup("swtpm"), g_strdup("socket"),
145 g_strdup("--tpmstate"), swtpm_argv_tpmstate,
146 g_strdup("--ctrl"), swtpm_argv_ctrl,
147 g_strdup("--tpm2"),
148 NULL
149 };
150 gboolean succ;
151 unsigned i;
152
153 succ = tpm_util_swtpm_has_tpm2();
154 if (!succ) {
155 goto cleanup;
156 }
157
158 *addr = g_new0(SocketAddress, 1);
159 (*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
160 (*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
161
162 succ = g_spawn_async(NULL, swtpm_argv, NULL, G_SPAWN_SEARCH_PATH,
163 NULL, NULL, pid, error);
164
165cleanup:
166 for (i = 0; swtpm_argv[i]; i++) {
167 g_free(swtpm_argv[i]);
168 }
169
170 return succ;
171}
172
173void tpm_util_swtpm_kill(GPid pid)
174{
175 int n;
176
177 if (!pid) {
178 return;
179 }
180
181 g_spawn_close_pid(pid);
182
183 n = kill(pid, 0);
184 if (n < 0) {
185 return;
186 }
187
188 kill(pid, SIGKILL);
189}
b1e4b7c6
SB
190
191void tpm_util_migrate(QTestState *who, const char *uri)
192{
193 QDict *rsp;
194 gchar *cmd;
195
196 cmd = g_strdup_printf("{ 'execute': 'migrate',"
197 "'arguments': { 'uri': '%s' } }",
198 uri);
199 rsp = qtest_qmp(who, cmd);
200 g_free(cmd);
201 g_assert(qdict_haskey(rsp, "return"));
202 qobject_unref(rsp);
203}
204
205/*
206 * Events can get in the way of responses we are actually waiting for.
207 */
208static QDict *tpm_util_wait_command(QTestState *who, const char *command)
209{
210 const char *event_string;
211 QDict *response;
212
213 response = qtest_qmp(who, command);
214
215 while (qdict_haskey(response, "event")) {
216 /* OK, it was an event */
217 event_string = qdict_get_str(response, "event");
218 if (!strcmp(event_string, "STOP")) {
219 got_stop = true;
220 }
221 qobject_unref(response);
222 response = qtest_qmp_receive(who);
223 }
224 return response;
225}
226
227void tpm_util_wait_for_migration_complete(QTestState *who)
228{
229 while (true) {
230 QDict *rsp, *rsp_return;
231 bool completed;
232 const char *status;
233
234 rsp = tpm_util_wait_command(who, "{ 'execute': 'query-migrate' }");
235 rsp_return = qdict_get_qdict(rsp, "return");
236 status = qdict_get_str(rsp_return, "status");
237 completed = strcmp(status, "completed") == 0;
238 g_assert_cmpstr(status, !=, "failed");
239 qobject_unref(rsp);
240 if (completed) {
241 return;
242 }
243 usleep(1000);
244 }
245}
246
247void tpm_util_migration_start_qemu(QTestState **src_qemu,
248 QTestState **dst_qemu,
249 SocketAddress *src_tpm_addr,
250 SocketAddress *dst_tpm_addr,
251 const char *miguri)
252{
253 char *src_qemu_args, *dst_qemu_args;
254
255 src_qemu_args = g_strdup_printf(
256 "-chardev socket,id=chr,path=%s "
257 "-tpmdev emulator,id=dev,chardev=chr "
258 "-device tpm-crb,tpmdev=dev ",
259 src_tpm_addr->u.q_unix.path);
260
261 *src_qemu = qtest_init(src_qemu_args);
262
263 dst_qemu_args = g_strdup_printf(
264 "-chardev socket,id=chr,path=%s "
265 "-tpmdev emulator,id=dev,chardev=chr "
266 "-device tpm-crb,tpmdev=dev "
267 "-incoming %s",
268 dst_tpm_addr->u.q_unix.path,
269 miguri);
270
271 *dst_qemu = qtest_init(dst_qemu_args);
272
273 free(src_qemu_args);
274 free(dst_qemu_args);
275}