]> git.proxmox.com Git - mirror_qemu.git/blob - hw/tpm/tpm_emulator.c
tpm: tpm_emulator: get and set buffer size of device
[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 /* data structures */
64 typedef struct TPMEmulator {
65 TPMBackend parent;
66
67 TPMEmulatorOptions *options;
68 CharBackend ctrl_chr;
69 QIOChannel *data_ioc;
70 TPMVersion tpm_version;
71 ptm_cap caps; /* capabilities of the TPM */
72 uint8_t cur_locty_number; /* last set locality */
73 Error *migration_blocker;
74
75 QemuMutex mutex;
76 } TPMEmulator;
77
78
79 static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
80 size_t msg_len_in, size_t msg_len_out)
81 {
82 CharBackend *dev = &tpm->ctrl_chr;
83 uint32_t cmd_no = cpu_to_be32(cmd);
84 ssize_t n = sizeof(uint32_t) + msg_len_in;
85 uint8_t *buf = NULL;
86 int ret = -1;
87
88 qemu_mutex_lock(&tpm->mutex);
89
90 buf = g_alloca(n);
91 memcpy(buf, &cmd_no, sizeof(cmd_no));
92 memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
93
94 n = qemu_chr_fe_write_all(dev, buf, n);
95 if (n <= 0) {
96 goto end;
97 }
98
99 if (msg_len_out != 0) {
100 n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
101 if (n <= 0) {
102 goto end;
103 }
104 }
105
106 ret = 0;
107
108 end:
109 qemu_mutex_unlock(&tpm->mutex);
110 return ret;
111 }
112
113 static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
114 const uint8_t *in, uint32_t in_len,
115 uint8_t *out, uint32_t out_len,
116 bool *selftest_done,
117 Error **err)
118 {
119 ssize_t ret;
120 bool is_selftest = false;
121 const struct tpm_resp_hdr *hdr = NULL;
122
123 if (selftest_done) {
124 *selftest_done = false;
125 is_selftest = tpm_util_is_selftest(in, in_len);
126 }
127
128 ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err);
129 if (ret != 0) {
130 return -1;
131 }
132
133 ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, sizeof(*hdr),
134 err);
135 if (ret != 0) {
136 return -1;
137 }
138
139 hdr = (struct tpm_resp_hdr *)out;
140 out += sizeof(*hdr);
141 ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out,
142 be32_to_cpu(hdr->len) - sizeof(*hdr) , err);
143 if (ret != 0) {
144 return -1;
145 }
146
147 if (is_selftest) {
148 *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
149 }
150
151 return 0;
152 }
153
154 static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
155 Error **errp)
156 {
157 ptm_loc loc;
158
159 DPRINTF("%s : locality: 0x%x", __func__, locty_number);
160
161 if (tpm_emu->cur_locty_number == locty_number) {
162 return 0;
163 }
164
165 DPRINTF("setting locality : 0x%x", locty_number);
166 loc.u.req.loc = locty_number;
167 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc,
168 sizeof(loc), sizeof(loc)) < 0) {
169 error_setg(errp, "tpm-emulator: could not set locality : %s",
170 strerror(errno));
171 return -1;
172 }
173
174 loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
175 if (loc.u.resp.tpm_result != 0) {
176 error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x",
177 loc.u.resp.tpm_result);
178 return -1;
179 }
180
181 tpm_emu->cur_locty_number = locty_number;
182
183 return 0;
184 }
185
186 static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
187 {
188 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
189 Error *err = NULL;
190
191 DPRINTF("processing TPM command");
192
193 if (tpm_emulator_set_locality(tpm_emu, cmd->locty, &err) < 0) {
194 goto error;
195 }
196
197 if (tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len,
198 cmd->out, cmd->out_len,
199 &cmd->selftest_done, &err) < 0) {
200 goto error;
201 }
202
203 return;
204
205 error:
206 tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
207 error_report_err(err);
208 }
209
210 static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
211 {
212 DPRINTF("%s", __func__);
213 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY,
214 &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
215 error_report("tpm-emulator: probing failed : %s", strerror(errno));
216 return -1;
217 }
218
219 tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
220
221 DPRINTF("capabilities : 0x%"PRIx64, tpm_emu->caps);
222
223 return 0;
224 }
225
226 static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
227 {
228 ptm_cap caps = 0;
229 const char *tpm = NULL;
230
231 /* check for min. required capabilities */
232 switch (tpm_emu->tpm_version) {
233 case TPM_VERSION_1_2:
234 caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
235 PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP |
236 PTM_CAP_SET_BUFFERSIZE;
237 tpm = "1.2";
238 break;
239 case TPM_VERSION_2_0:
240 caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
241 PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
242 PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
243 tpm = "2";
244 break;
245 case TPM_VERSION_UNSPEC:
246 error_report("tpm-emulator: TPM version has not been set");
247 return -1;
248 }
249
250 if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
251 error_report("tpm-emulator: TPM does not implement minimum set of "
252 "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
253 return -1;
254 }
255
256 return 0;
257 }
258
259 static int tpm_emulator_stop_tpm(TPMBackend *tb)
260 {
261 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
262 ptm_res res;
263
264 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
265 error_report("tpm-emulator: Could not stop TPM: %s",
266 strerror(errno));
267 return -1;
268 }
269
270 res = be32_to_cpu(res);
271 if (res) {
272 error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x", res);
273 return -1;
274 }
275
276 return 0;
277 }
278
279 static int tpm_emulator_set_buffer_size(TPMBackend *tb,
280 size_t wanted_size,
281 size_t *actual_size)
282 {
283 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
284 ptm_setbuffersize psbs;
285
286 if (tpm_emulator_stop_tpm(tb) < 0) {
287 return -1;
288 }
289
290 psbs.u.req.buffersize = cpu_to_be32(wanted_size);
291
292 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
293 sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
294 error_report("tpm-emulator: Could not set buffer size: %s",
295 strerror(errno));
296 return -1;
297 }
298
299 psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result);
300 if (psbs.u.resp.tpm_result != 0) {
301 error_report("tpm-emulator: TPM result for set buffer size : 0x%x",
302 psbs.u.resp.tpm_result);
303 return -1;
304 }
305
306 if (actual_size) {
307 *actual_size = be32_to_cpu(psbs.u.resp.buffersize);
308 }
309
310 DPRINTF("buffer size: %u, min: %u, max: %u\n",
311 be32_to_cpu(psbs.u.resp.buffersize),
312 be32_to_cpu(psbs.u.resp.minsize),
313 be32_to_cpu(psbs.u.resp.maxsize));
314
315 return 0;
316 }
317
318 static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
319 {
320 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
321 ptm_init init;
322 ptm_res res;
323
324 if (buffersize != 0 &&
325 tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
326 goto err_exit;
327 }
328
329 DPRINTF("%s", __func__);
330 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
331 sizeof(init)) < 0) {
332 error_report("tpm-emulator: could not send INIT: %s",
333 strerror(errno));
334 goto err_exit;
335 }
336
337 res = be32_to_cpu(init.u.resp.tpm_result);
338 if (res) {
339 error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x", res);
340 goto err_exit;
341 }
342 return 0;
343
344 err_exit:
345 return -1;
346 }
347
348 static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
349 {
350 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
351 ptm_est est;
352
353 DPRINTF("%s", __func__);
354 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est,
355 0, sizeof(est)) < 0) {
356 error_report("tpm-emulator: Could not get the TPM established flag: %s",
357 strerror(errno));
358 return false;
359 }
360 DPRINTF("established flag: %0x", est.u.resp.bit);
361
362 return (est.u.resp.bit != 0);
363 }
364
365 static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
366 uint8_t locty)
367 {
368 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
369 ptm_reset_est reset_est;
370 ptm_res res;
371
372 /* only a TPM 2.0 will support this */
373 if (tpm_emu->tpm_version != TPM_VERSION_2_0) {
374 return 0;
375 }
376
377 reset_est.u.req.loc = tpm_emu->cur_locty_number;
378 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED,
379 &reset_est, sizeof(reset_est),
380 sizeof(reset_est)) < 0) {
381 error_report("tpm-emulator: Could not reset the establishment bit: %s",
382 strerror(errno));
383 return -1;
384 }
385
386 res = be32_to_cpu(reset_est.u.resp.tpm_result);
387 if (res) {
388 error_report("tpm-emulator: TPM result for rest establixhed flag: 0x%x",
389 res);
390 return -1;
391 }
392
393 return 0;
394 }
395
396 static void tpm_emulator_cancel_cmd(TPMBackend *tb)
397 {
398 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
399 ptm_res res;
400
401 if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) {
402 DPRINTF("Backend does not support CANCEL_TPM_CMD");
403 return;
404 }
405
406 /* FIXME: make the function non-blocking, or it may block a VCPU */
407 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
408 sizeof(res)) < 0) {
409 error_report("tpm-emulator: Could not cancel command: %s",
410 strerror(errno));
411 } else if (res != 0) {
412 error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
413 be32_to_cpu(res));
414 }
415 }
416
417 static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
418 {
419 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
420
421 return tpm_emu->tpm_version;
422 }
423
424 static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
425 {
426 size_t actual_size;
427
428 if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) {
429 return 4096;
430 }
431
432 return actual_size;
433 }
434
435 static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
436 {
437 Error *err = NULL;
438
439 error_setg(&tpm_emu->migration_blocker,
440 "Migration disabled: TPM emulator not yet migratable");
441 migrate_add_blocker(tpm_emu->migration_blocker, &err);
442 if (err) {
443 error_report_err(err);
444 error_free(tpm_emu->migration_blocker);
445 tpm_emu->migration_blocker = NULL;
446
447 return -1;
448 }
449
450 return 0;
451 }
452
453 static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
454 {
455 ptm_res res;
456 Error *err = NULL;
457 int fds[2] = { -1, -1 };
458
459 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
460 error_report("tpm-emulator: Failed to create socketpair");
461 return -1;
462 }
463
464 qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
465
466 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0,
467 sizeof(res)) < 0 || res != 0) {
468 error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
469 strerror(errno));
470 goto err_exit;
471 }
472
473 tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));
474 if (err) {
475 error_prepend(&err, "tpm-emulator: Failed to create io channel: ");
476 error_report_err(err);
477 goto err_exit;
478 }
479
480 closesocket(fds[1]);
481
482 return 0;
483
484 err_exit:
485 closesocket(fds[0]);
486 closesocket(fds[1]);
487 return -1;
488 }
489
490 static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
491 {
492 const char *value;
493
494 value = qemu_opt_get(opts, "chardev");
495 if (value) {
496 Error *err = NULL;
497 Chardev *dev = qemu_chr_find(value);
498
499 if (!dev) {
500 error_report("tpm-emulator: tpm chardev '%s' not found.", value);
501 goto err;
502 }
503
504 if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
505 error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
506 value);
507 error_report_err(err);
508 goto err;
509 }
510
511 tpm_emu->options->chardev = g_strdup(value);
512 }
513
514 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
515 goto err;
516 }
517
518 /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
519 * by passthrough driver, which not yet using GIOChannel.
520 */
521 if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
522 &tpm_emu->tpm_version)) {
523 error_report("'%s' is not emulating TPM device. Error: %s",
524 tpm_emu->options->chardev, strerror(errno));
525 goto err;
526 }
527
528 DPRINTF("TPM Version %s", tpm_emu->tpm_version == TPM_VERSION_1_2 ? "1.2" :
529 (tpm_emu->tpm_version == TPM_VERSION_2_0 ? "2.0" : "Unspecified"));
530
531 if (tpm_emulator_probe_caps(tpm_emu) ||
532 tpm_emulator_check_caps(tpm_emu)) {
533 goto err;
534 }
535
536 return tpm_emulator_block_migration(tpm_emu);
537
538 err:
539 DPRINTF("Startup error");
540 return -1;
541 }
542
543 static TPMBackend *tpm_emulator_create(QemuOpts *opts)
544 {
545 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
546
547 if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
548 object_unref(OBJECT(tb));
549 return NULL;
550 }
551
552 return tb;
553 }
554
555 static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
556 {
557 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
558 TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
559
560 options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
561 options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
562
563 return options;
564 }
565
566 static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
567 TPM_STANDARD_CMDLINE_OPTS,
568 {
569 .name = "chardev",
570 .type = QEMU_OPT_STRING,
571 .help = "Character device to use for out-of-band control messages",
572 },
573 { /* end of list */ },
574 };
575
576 static void tpm_emulator_inst_init(Object *obj)
577 {
578 TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
579
580 DPRINTF("%s", __func__);
581 tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
582 tpm_emu->cur_locty_number = ~0;
583 qemu_mutex_init(&tpm_emu->mutex);
584 }
585
586 /*
587 * Gracefully shut down the external TPM
588 */
589 static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
590 {
591 ptm_res res;
592
593 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) {
594 error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
595 strerror(errno));
596 } else if (res != 0) {
597 error_report("tpm-emulator: TPM result for sutdown: 0x%x",
598 be32_to_cpu(res));
599 }
600 }
601
602 static void tpm_emulator_inst_finalize(Object *obj)
603 {
604 TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
605
606 tpm_emulator_shutdown(tpm_emu);
607
608 object_unref(OBJECT(tpm_emu->data_ioc));
609
610 qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false);
611
612 qapi_free_TPMEmulatorOptions(tpm_emu->options);
613
614 if (tpm_emu->migration_blocker) {
615 migrate_del_blocker(tpm_emu->migration_blocker);
616 error_free(tpm_emu->migration_blocker);
617 }
618
619 qemu_mutex_destroy(&tpm_emu->mutex);
620 }
621
622 static void tpm_emulator_class_init(ObjectClass *klass, void *data)
623 {
624 TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
625
626 tbc->type = TPM_TYPE_EMULATOR;
627 tbc->opts = tpm_emulator_cmdline_opts;
628 tbc->desc = "TPM emulator backend driver";
629 tbc->create = tpm_emulator_create;
630 tbc->startup_tpm = tpm_emulator_startup_tpm;
631 tbc->cancel_cmd = tpm_emulator_cancel_cmd;
632 tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
633 tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
634 tbc->get_tpm_version = tpm_emulator_get_tpm_version;
635 tbc->get_buffer_size = tpm_emulator_get_buffer_size;
636 tbc->get_tpm_options = tpm_emulator_get_tpm_options;
637
638 tbc->handle_request = tpm_emulator_handle_request;
639 }
640
641 static const TypeInfo tpm_emulator_info = {
642 .name = TYPE_TPM_EMULATOR,
643 .parent = TYPE_TPM_BACKEND,
644 .instance_size = sizeof(TPMEmulator),
645 .class_init = tpm_emulator_class_init,
646 .instance_init = tpm_emulator_inst_init,
647 .instance_finalize = tpm_emulator_inst_finalize,
648 };
649
650 static void tpm_emulator_register(void)
651 {
652 type_register_static(&tpm_emulator_info);
653 }
654
655 type_init(tpm_emulator_register)