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