]> git.proxmox.com Git - mirror_qemu.git/blob - hw/tpm/tpm_emulator.c
Merge remote-tracking branch 'remotes/huth/tags/pull-request-2017-10-16' into staging
[mirror_qemu.git] / hw / tpm / tpm_emulator.c
1 /*
2 * Emulator TPM driver
3 *
4 * Copyright (c) 2017 Intel Corporation
5 * Author: Amarnath Valluri <amarnath.valluri@intel.com>
6 *
7 * Copyright (c) 2010 - 2013 IBM Corporation
8 * Authors:
9 * Stefan Berger <stefanb@us.ibm.com>
10 *
11 * Copyright (C) 2011 IAIK, Graz University of Technology
12 * Author: Andreas Niederl
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, see <http://www.gnu.org/licenses/>
26 *
27 */
28
29 #include "qemu/osdep.h"
30 #include "qemu/error-report.h"
31 #include "qemu/sockets.h"
32 #include "io/channel-socket.h"
33 #include "sysemu/tpm_backend.h"
34 #include "tpm_int.h"
35 #include "hw/hw.h"
36 #include "hw/i386/pc.h"
37 #include "tpm_util.h"
38 #include "tpm_ioctl.h"
39 #include "migration/blocker.h"
40 #include "qapi/error.h"
41 #include "qapi/clone-visitor.h"
42 #include "chardev/char-fe.h"
43
44 #include <fcntl.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <stdio.h>
48
49 #define DEBUG_TPM 0
50
51 #define DPRINTF(fmt, ...) do { \
52 if (DEBUG_TPM) { \
53 fprintf(stderr, "tpm-emulator:"fmt"\n", ## __VA_ARGS__); \
54 } \
55 } while (0)
56
57 #define TYPE_TPM_EMULATOR "tpm-emulator"
58 #define TPM_EMULATOR(obj) \
59 OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
60
61 #define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
62
63 static const TPMDriverOps tpm_emulator_driver;
64
65 /* data structures */
66 typedef struct TPMEmulator {
67 TPMBackend parent;
68
69 TPMEmulatorOptions *options;
70 CharBackend ctrl_chr;
71 QIOChannel *data_ioc;
72 TPMVersion tpm_version;
73 ptm_cap caps; /* capabilities of the TPM */
74 uint8_t cur_locty_number; /* last set locality */
75 Error *migration_blocker;
76 } TPMEmulator;
77
78
79 static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long cmd, void *msg,
80 size_t msg_len_in, size_t msg_len_out)
81 {
82 uint32_t cmd_no = cpu_to_be32(cmd);
83 ssize_t n = sizeof(uint32_t) + msg_len_in;
84 uint8_t *buf = NULL;
85
86 buf = g_alloca(n);
87 memcpy(buf, &cmd_no, sizeof(cmd_no));
88 memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
89
90 n = qemu_chr_fe_write_all(dev, buf, n);
91 if (n <= 0) {
92 return -1;
93 }
94
95 if (msg_len_out != 0) {
96 n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
97 if (n <= 0) {
98 return -1;
99 }
100 }
101
102 return 0;
103 }
104
105 static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
106 const uint8_t *in, uint32_t in_len,
107 uint8_t *out, uint32_t out_len,
108 bool *selftest_done,
109 Error **err)
110 {
111 ssize_t ret;
112 bool is_selftest = false;
113 const struct tpm_resp_hdr *hdr = NULL;
114
115 if (selftest_done) {
116 *selftest_done = false;
117 is_selftest = tpm_util_is_selftest(in, in_len);
118 }
119
120 ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err);
121 if (ret != 0) {
122 return -1;
123 }
124
125 ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, sizeof(*hdr),
126 err);
127 if (ret != 0) {
128 return -1;
129 }
130
131 hdr = (struct tpm_resp_hdr *)out;
132 out += sizeof(*hdr);
133 ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out,
134 be32_to_cpu(hdr->len) - sizeof(*hdr) , err);
135 if (ret != 0) {
136 return -1;
137 }
138
139 if (is_selftest) {
140 *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
141 }
142
143 return 0;
144 }
145
146 static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number)
147 {
148 ptm_loc loc;
149
150 DPRINTF("%s : locality: 0x%x", __func__, locty_number);
151
152 if (tpm_emu->cur_locty_number == locty_number) {
153 return 0;
154 }
155
156 DPRINTF("setting locality : 0x%x", locty_number);
157 loc.u.req.loc = locty_number;
158 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SET_LOCALITY, &loc,
159 sizeof(loc), sizeof(loc)) < 0) {
160 error_report("tpm-emulator: could not set locality : %s",
161 strerror(errno));
162 return -1;
163 }
164
165 loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
166 if (loc.u.resp.tpm_result != 0) {
167 error_report("tpm-emulator: TPM result for set locality : 0x%x",
168 loc.u.resp.tpm_result);
169 return -1;
170 }
171
172 tpm_emu->cur_locty_number = locty_number;
173
174 return 0;
175 }
176
177 static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
178 {
179 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
180 TPMLocality *locty = NULL;
181 bool selftest_done = false;
182 Error *err = NULL;
183
184 DPRINTF("processing command type %d", cmd);
185
186 switch (cmd) {
187 case TPM_BACKEND_CMD_PROCESS_CMD:
188 locty = tb->tpm_state->locty_data;
189 if (tpm_emulator_set_locality(tpm_emu,
190 tb->tpm_state->locty_number) < 0 ||
191 tpm_emulator_unix_tx_bufs(tpm_emu, locty->w_buffer.buffer,
192 locty->w_offset, locty->r_buffer.buffer,
193 locty->r_buffer.size, &selftest_done,
194 &err) < 0) {
195 tpm_util_write_fatal_error_response(locty->r_buffer.buffer,
196 locty->r_buffer.size);
197 error_report_err(err);
198 }
199
200 tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,
201 selftest_done);
202
203 break;
204 case TPM_BACKEND_CMD_INIT:
205 case TPM_BACKEND_CMD_END:
206 case TPM_BACKEND_CMD_TPM_RESET:
207 /* nothing to do */
208 break;
209 }
210 }
211
212 static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
213 {
214 DPRINTF("%s", __func__);
215 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_GET_CAPABILITY,
216 &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
217 error_report("tpm-emulator: probing failed : %s", strerror(errno));
218 return -1;
219 }
220
221 tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
222
223 DPRINTF("capabilities : 0x%"PRIx64, tpm_emu->caps);
224
225 return 0;
226 }
227
228 static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
229 {
230 ptm_cap caps = 0;
231 const char *tpm = NULL;
232
233 /* check for min. required capabilities */
234 switch (tpm_emu->tpm_version) {
235 case TPM_VERSION_1_2:
236 caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
237 PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD;
238 tpm = "1.2";
239 break;
240 case TPM_VERSION_2_0:
241 caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
242 PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
243 PTM_CAP_SET_DATAFD;
244 tpm = "2";
245 break;
246 case TPM_VERSION_UNSPEC:
247 error_report("tpm-emulator: TPM version has not been set");
248 return -1;
249 }
250
251 if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
252 error_report("tpm-emulator: TPM does not implement minimum set of "
253 "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
254 return -1;
255 }
256
257 return 0;
258 }
259
260 static int tpm_emulator_startup_tpm(TPMBackend *tb)
261 {
262 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
263 ptm_init init;
264 ptm_res res;
265
266 DPRINTF("%s", __func__);
267 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_INIT, &init, sizeof(init),
268 sizeof(init)) < 0) {
269 error_report("tpm-emulator: could not send INIT: %s",
270 strerror(errno));
271 goto err_exit;
272 }
273
274 res = be32_to_cpu(init.u.resp.tpm_result);
275 if (res) {
276 error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x", res);
277 goto err_exit;
278 }
279 return 0;
280
281 err_exit:
282 return -1;
283 }
284
285 static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
286 {
287 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
288 ptm_est est;
289
290 DPRINTF("%s", __func__);
291 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_GET_TPMESTABLISHED, &est,
292 0, sizeof(est)) < 0) {
293 error_report("tpm-emulator: Could not get the TPM established flag: %s",
294 strerror(errno));
295 return false;
296 }
297 DPRINTF("established flag: %0x", est.u.resp.bit);
298
299 return (est.u.resp.bit != 0);
300 }
301
302 static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
303 uint8_t locty)
304 {
305 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
306 ptm_reset_est reset_est;
307 ptm_res res;
308
309 /* only a TPM 2.0 will support this */
310 if (tpm_emu->tpm_version != TPM_VERSION_2_0) {
311 return 0;
312 }
313
314 reset_est.u.req.loc = tpm_emu->cur_locty_number;
315 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_RESET_TPMESTABLISHED,
316 &reset_est, sizeof(reset_est),
317 sizeof(reset_est)) < 0) {
318 error_report("tpm-emulator: Could not reset the establishment bit: %s",
319 strerror(errno));
320 return -1;
321 }
322
323 res = be32_to_cpu(reset_est.u.resp.tpm_result);
324 if (res) {
325 error_report("tpm-emulator: TPM result for rest establixhed flag: 0x%x",
326 res);
327 return -1;
328 }
329
330 return 0;
331 }
332
333 static void tpm_emulator_cancel_cmd(TPMBackend *tb)
334 {
335 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
336 ptm_res res;
337
338 if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) {
339 DPRINTF("Backend does not support CANCEL_TPM_CMD");
340 return;
341 }
342
343 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_CANCEL_TPM_CMD, &res, 0,
344 sizeof(res)) < 0) {
345 error_report("tpm-emulator: Could not cancel command: %s",
346 strerror(errno));
347 } else if (res != 0) {
348 error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
349 be32_to_cpu(res));
350 }
351 }
352
353 static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
354 {
355 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
356
357 return tpm_emu->tpm_version;
358 }
359
360 static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
361 {
362 Error *err = NULL;
363
364 error_setg(&tpm_emu->migration_blocker,
365 "Migration disabled: TPM emulator not yet migratable");
366 migrate_add_blocker(tpm_emu->migration_blocker, &err);
367 if (err) {
368 error_report_err(err);
369 error_free(tpm_emu->migration_blocker);
370 tpm_emu->migration_blocker = NULL;
371
372 return -1;
373 }
374
375 return 0;
376 }
377
378 static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
379 {
380 ptm_res res;
381 Error *err = NULL;
382 int fds[2] = { -1, -1 };
383
384 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
385 error_report("tpm-emulator: Failed to create socketpair");
386 return -1;
387 }
388
389 qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
390
391 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SET_DATAFD, &res, 0,
392 sizeof(res)) || res != 0) {
393 error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
394 strerror(errno));
395 goto err_exit;
396 }
397
398 tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));
399 if (err) {
400 error_prepend(&err, "tpm-emulator: Failed to create io channel: ");
401 error_report_err(err);
402 goto err_exit;
403 }
404
405 closesocket(fds[1]);
406
407 return 0;
408
409 err_exit:
410 closesocket(fds[0]);
411 closesocket(fds[1]);
412 return -1;
413 }
414
415 static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
416 {
417 const char *value;
418
419 value = qemu_opt_get(opts, "chardev");
420 if (value) {
421 Error *err = NULL;
422 Chardev *dev = qemu_chr_find(value);
423
424 if (!dev) {
425 error_report("tpm-emulator: tpm chardev '%s' not found.", value);
426 goto err;
427 }
428
429 if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
430 error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
431 value);
432 error_report_err(err);
433 goto err;
434 }
435
436 tpm_emu->options->chardev = g_strdup(value);
437 }
438
439 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
440 goto err;
441 }
442
443 /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
444 * by passthrough driver, which not yet using GIOChannel.
445 */
446 if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
447 &tpm_emu->tpm_version)) {
448 error_report("'%s' is not emulating TPM device. Error: %s",
449 tpm_emu->options->chardev, strerror(errno));
450 goto err;
451 }
452
453 DPRINTF("TPM Version %s", tpm_emu->tpm_version == TPM_VERSION_1_2 ? "1.2" :
454 (tpm_emu->tpm_version == TPM_VERSION_2_0 ? "2.0" : "Unspecified"));
455
456 if (tpm_emulator_probe_caps(tpm_emu) ||
457 tpm_emulator_check_caps(tpm_emu)) {
458 goto err;
459 }
460
461 return tpm_emulator_block_migration(tpm_emu);
462
463 err:
464 DPRINTF("Startup error");
465 return -1;
466 }
467
468 static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
469 {
470 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
471
472 tb->id = g_strdup(id);
473
474 if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
475 goto err_exit;
476 }
477
478 return tb;
479
480 err_exit:
481 object_unref(OBJECT(tb));
482
483 return NULL;
484 }
485
486 static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
487 {
488 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
489 TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
490
491 options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
492 options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
493
494 return options;
495 }
496
497 static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
498 TPM_STANDARD_CMDLINE_OPTS,
499 {
500 .name = "chardev",
501 .type = QEMU_OPT_STRING,
502 .help = "Character device to use for out-of-band control messages",
503 },
504 { /* end of list */ },
505 };
506
507 static const TPMDriverOps tpm_emulator_driver = {
508 .type = TPM_TYPE_EMULATOR,
509 .opts = tpm_emulator_cmdline_opts,
510 .desc = "TPM emulator backend driver",
511
512 .create = tpm_emulator_create,
513 .startup_tpm = tpm_emulator_startup_tpm,
514 .cancel_cmd = tpm_emulator_cancel_cmd,
515 .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,
516 .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,
517 .get_tpm_version = tpm_emulator_get_tpm_version,
518 .get_tpm_options = tpm_emulator_get_tpm_options,
519 };
520
521 static void tpm_emulator_inst_init(Object *obj)
522 {
523 TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
524
525 DPRINTF("%s", __func__);
526 tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
527 tpm_emu->cur_locty_number = ~0;
528 }
529
530 /*
531 * Gracefully shut down the external TPM
532 */
533 static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
534 {
535 ptm_res res;
536
537 if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SHUTDOWN, &res, 0,
538 sizeof(res)) < 0) {
539 error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
540 strerror(errno));
541 } else if (res != 0) {
542 error_report("tpm-emulator: TPM result for sutdown: 0x%x",
543 be32_to_cpu(res));
544 }
545 }
546
547 static void tpm_emulator_inst_finalize(Object *obj)
548 {
549 TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
550
551 tpm_emulator_shutdown(tpm_emu);
552
553 object_unref(OBJECT(tpm_emu->data_ioc));
554
555 qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false);
556
557 qapi_free_TPMEmulatorOptions(tpm_emu->options);
558
559 if (tpm_emu->migration_blocker) {
560 migrate_del_blocker(tpm_emu->migration_blocker);
561 error_free(tpm_emu->migration_blocker);
562 }
563 }
564
565 static void tpm_emulator_class_init(ObjectClass *klass, void *data)
566 {
567 TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
568 tbc->ops = &tpm_emulator_driver;
569 tbc->handle_request = tpm_emulator_handle_request;
570 }
571
572 static const TypeInfo tpm_emulator_info = {
573 .name = TYPE_TPM_EMULATOR,
574 .parent = TYPE_TPM_BACKEND,
575 .instance_size = sizeof(TPMEmulator),
576 .class_init = tpm_emulator_class_init,
577 .instance_init = tpm_emulator_inst_init,
578 .instance_finalize = tpm_emulator_inst_finalize,
579 };
580
581 static void tpm_emulator_register(void)
582 {
583 type_register_static(&tpm_emulator_info);
584 tpm_register_driver(&tpm_emulator_driver);
585 }
586
587 type_init(tpm_emulator_register)