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, 2018 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/module.h" |
32 | #include "qemu/sockets.h" |
33 | #include "io/channel-socket.h" |
34 | #include "sysemu/tpm_backend.h" |
35 | #include "tpm_int.h" |
36 | #include "tpm_util.h" |
37 | #include "tpm_ioctl.h" |
38 | #include "migration/blocker.h" |
39 | #include "migration/vmstate.h" |
40 | #include "qapi/error.h" |
41 | #include "qapi/clone-visitor.h" |
42 | #include "qapi/qapi-visit-tpm.h" |
43 | #include "chardev/char-fe.h" |
44 | #include "trace.h" |
45 | |
46 | #define TYPE_TPM_EMULATOR "tpm-emulator" |
47 | #define TPM_EMULATOR(obj) \ |
48 | OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR) |
49 | |
50 | #define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap)) |
51 | |
52 | /* data structures */ |
53 | |
54 | /* blobs from the TPM; part of VM state when migrating */ |
55 | typedef struct TPMBlobBuffers { |
56 | uint32_t permanent_flags; |
57 | TPMSizedBuffer permanent; |
58 | |
59 | uint32_t volatil_flags; |
60 | TPMSizedBuffer volatil; |
61 | |
62 | uint32_t savestate_flags; |
63 | TPMSizedBuffer savestate; |
64 | } TPMBlobBuffers; |
65 | |
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 | |
77 | QemuMutex mutex; |
78 | |
79 | unsigned int established_flag:1; |
80 | unsigned int established_flag_cached:1; |
81 | |
82 | TPMBlobBuffers state_blobs; |
83 | } TPMEmulator; |
84 | |
85 | struct tpm_error { |
86 | uint32_t tpm_result; |
87 | const char *string; |
88 | }; |
89 | |
90 | static const struct tpm_error tpm_errors[] = { |
91 | /* TPM 1.2 error codes */ |
92 | { TPM_BAD_PARAMETER , "a parameter is bad" }, |
93 | { TPM_FAIL , "operation failed" }, |
94 | { TPM_KEYNOTFOUND , "key could not be found" }, |
95 | { TPM_BAD_PARAM_SIZE , "bad parameter size" }, |
96 | { TPM_ENCRYPT_ERROR , "encryption error" }, |
97 | { TPM_DECRYPT_ERROR , "decryption error" }, |
98 | { TPM_BAD_KEY_PROPERTY, "bad key property" }, |
99 | { TPM_BAD_MODE , "bad (encryption) mode" }, |
100 | { TPM_BAD_VERSION , "bad version identifier" }, |
101 | { TPM_BAD_LOCALITY , "bad locality" }, |
102 | /* TPM 2 error codes */ |
103 | { TPM_RC_FAILURE , "operation failed" }, |
104 | { TPM_RC_LOCALITY , "bad locality" }, |
105 | { TPM_RC_INSUFFICIENT, "insufficient amount of data" }, |
106 | }; |
107 | |
108 | static const char *tpm_emulator_strerror(uint32_t tpm_result) |
109 | { |
110 | size_t i; |
111 | |
112 | for (i = 0; i < ARRAY_SIZE(tpm_errors); i++) { |
113 | if (tpm_errors[i].tpm_result == tpm_result) { |
114 | return tpm_errors[i].string; |
115 | } |
116 | } |
117 | return "" ; |
118 | } |
119 | |
120 | static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg, |
121 | size_t msg_len_in, size_t msg_len_out) |
122 | { |
123 | CharBackend *dev = &tpm->ctrl_chr; |
124 | uint32_t cmd_no = cpu_to_be32(cmd); |
125 | ssize_t n = sizeof(uint32_t) + msg_len_in; |
126 | uint8_t *buf = NULL; |
127 | int ret = -1; |
128 | |
129 | qemu_mutex_lock(&tpm->mutex); |
130 | |
131 | buf = g_alloca(n); |
132 | memcpy(buf, &cmd_no, sizeof(cmd_no)); |
133 | memcpy(buf + sizeof(cmd_no), msg, msg_len_in); |
134 | |
135 | n = qemu_chr_fe_write_all(dev, buf, n); |
136 | if (n <= 0) { |
137 | goto end; |
138 | } |
139 | |
140 | if (msg_len_out != 0) { |
141 | n = qemu_chr_fe_read_all(dev, msg, msg_len_out); |
142 | if (n <= 0) { |
143 | goto end; |
144 | } |
145 | } |
146 | |
147 | ret = 0; |
148 | |
149 | end: |
150 | qemu_mutex_unlock(&tpm->mutex); |
151 | return ret; |
152 | } |
153 | |
154 | static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, |
155 | const uint8_t *in, uint32_t in_len, |
156 | uint8_t *out, uint32_t out_len, |
157 | bool *selftest_done, |
158 | Error **err) |
159 | { |
160 | ssize_t ret; |
161 | bool is_selftest = false; |
162 | |
163 | if (selftest_done) { |
164 | *selftest_done = false; |
165 | is_selftest = tpm_util_is_selftest(in, in_len); |
166 | } |
167 | |
168 | ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err); |
169 | if (ret != 0) { |
170 | return -1; |
171 | } |
172 | |
173 | ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, |
174 | sizeof(struct tpm_resp_hdr), err); |
175 | if (ret != 0) { |
176 | return -1; |
177 | } |
178 | |
179 | ret = qio_channel_read_all(tpm_emu->data_ioc, |
180 | (char *)out + sizeof(struct tpm_resp_hdr), |
181 | tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), err); |
182 | if (ret != 0) { |
183 | return -1; |
184 | } |
185 | |
186 | if (is_selftest) { |
187 | *selftest_done = tpm_cmd_get_errcode(out) == 0; |
188 | } |
189 | |
190 | return 0; |
191 | } |
192 | |
193 | static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number, |
194 | Error **errp) |
195 | { |
196 | ptm_loc loc; |
197 | |
198 | if (tpm_emu->cur_locty_number == locty_number) { |
199 | return 0; |
200 | } |
201 | |
202 | trace_tpm_emulator_set_locality(locty_number); |
203 | |
204 | memset(&loc, 0, sizeof(loc)); |
205 | loc.u.req.loc = locty_number; |
206 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc, |
207 | sizeof(loc), sizeof(loc)) < 0) { |
208 | error_setg(errp, "tpm-emulator: could not set locality : %s" , |
209 | strerror(errno)); |
210 | return -1; |
211 | } |
212 | |
213 | loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result); |
214 | if (loc.u.resp.tpm_result != 0) { |
215 | error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x" , |
216 | loc.u.resp.tpm_result); |
217 | return -1; |
218 | } |
219 | |
220 | tpm_emu->cur_locty_number = locty_number; |
221 | |
222 | return 0; |
223 | } |
224 | |
225 | static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd, |
226 | Error **errp) |
227 | { |
228 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
229 | |
230 | trace_tpm_emulator_handle_request(); |
231 | |
232 | if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 || |
233 | tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len, |
234 | cmd->out, cmd->out_len, |
235 | &cmd->selftest_done, errp) < 0) { |
236 | tpm_util_write_fatal_error_response(cmd->out, cmd->out_len); |
237 | } |
238 | } |
239 | |
240 | static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu) |
241 | { |
242 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY, |
243 | &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) { |
244 | error_report("tpm-emulator: probing failed : %s" , strerror(errno)); |
245 | return -1; |
246 | } |
247 | |
248 | tpm_emu->caps = be64_to_cpu(tpm_emu->caps); |
249 | |
250 | trace_tpm_emulator_probe_caps(tpm_emu->caps); |
251 | |
252 | return 0; |
253 | } |
254 | |
255 | static int tpm_emulator_check_caps(TPMEmulator *tpm_emu) |
256 | { |
257 | ptm_cap caps = 0; |
258 | const char *tpm = NULL; |
259 | |
260 | /* check for min. required capabilities */ |
261 | switch (tpm_emu->tpm_version) { |
262 | case TPM_VERSION_1_2: |
263 | caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | |
264 | PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP | |
265 | PTM_CAP_SET_BUFFERSIZE; |
266 | tpm = "1.2" ; |
267 | break; |
268 | case TPM_VERSION_2_0: |
269 | caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | |
270 | PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED | |
271 | PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE; |
272 | tpm = "2" ; |
273 | break; |
274 | case TPM_VERSION_UNSPEC: |
275 | error_report("tpm-emulator: TPM version has not been set" ); |
276 | return -1; |
277 | } |
278 | |
279 | if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) { |
280 | error_report("tpm-emulator: TPM does not implement minimum set of " |
281 | "required capabilities for TPM %s (0x%x)" , tpm, (int)caps); |
282 | return -1; |
283 | } |
284 | |
285 | return 0; |
286 | } |
287 | |
288 | static int tpm_emulator_stop_tpm(TPMBackend *tb) |
289 | { |
290 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
291 | ptm_res res; |
292 | |
293 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) { |
294 | error_report("tpm-emulator: Could not stop TPM: %s" , |
295 | strerror(errno)); |
296 | return -1; |
297 | } |
298 | |
299 | res = be32_to_cpu(res); |
300 | if (res) { |
301 | error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x %s" , res, |
302 | tpm_emulator_strerror(res)); |
303 | return -1; |
304 | } |
305 | |
306 | return 0; |
307 | } |
308 | |
309 | static int tpm_emulator_set_buffer_size(TPMBackend *tb, |
310 | size_t wanted_size, |
311 | size_t *actual_size) |
312 | { |
313 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
314 | ptm_setbuffersize psbs; |
315 | |
316 | if (tpm_emulator_stop_tpm(tb) < 0) { |
317 | return -1; |
318 | } |
319 | |
320 | psbs.u.req.buffersize = cpu_to_be32(wanted_size); |
321 | |
322 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs, |
323 | sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) { |
324 | error_report("tpm-emulator: Could not set buffer size: %s" , |
325 | strerror(errno)); |
326 | return -1; |
327 | } |
328 | |
329 | psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result); |
330 | if (psbs.u.resp.tpm_result != 0) { |
331 | error_report("tpm-emulator: TPM result for set buffer size : 0x%x %s" , |
332 | psbs.u.resp.tpm_result, |
333 | tpm_emulator_strerror(psbs.u.resp.tpm_result)); |
334 | return -1; |
335 | } |
336 | |
337 | if (actual_size) { |
338 | *actual_size = be32_to_cpu(psbs.u.resp.buffersize); |
339 | } |
340 | |
341 | trace_tpm_emulator_set_buffer_size( |
342 | be32_to_cpu(psbs.u.resp.buffersize), |
343 | be32_to_cpu(psbs.u.resp.minsize), |
344 | be32_to_cpu(psbs.u.resp.maxsize)); |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize, |
350 | bool is_resume) |
351 | { |
352 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
353 | ptm_init init = { |
354 | .u.req.init_flags = 0, |
355 | }; |
356 | ptm_res res; |
357 | |
358 | trace_tpm_emulator_startup_tpm_resume(is_resume, buffersize); |
359 | |
360 | if (buffersize != 0 && |
361 | tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) { |
362 | goto err_exit; |
363 | } |
364 | |
365 | if (is_resume) { |
366 | init.u.req.init_flags |= cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE); |
367 | } |
368 | |
369 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init), |
370 | sizeof(init)) < 0) { |
371 | error_report("tpm-emulator: could not send INIT: %s" , |
372 | strerror(errno)); |
373 | goto err_exit; |
374 | } |
375 | |
376 | res = be32_to_cpu(init.u.resp.tpm_result); |
377 | if (res) { |
378 | error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x %s" , res, |
379 | tpm_emulator_strerror(res)); |
380 | goto err_exit; |
381 | } |
382 | return 0; |
383 | |
384 | err_exit: |
385 | return -1; |
386 | } |
387 | |
388 | static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize) |
389 | { |
390 | return tpm_emulator_startup_tpm_resume(tb, buffersize, false); |
391 | } |
392 | |
393 | static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb) |
394 | { |
395 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
396 | ptm_est est; |
397 | |
398 | if (tpm_emu->established_flag_cached) { |
399 | return tpm_emu->established_flag; |
400 | } |
401 | |
402 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est, |
403 | 0, sizeof(est)) < 0) { |
404 | error_report("tpm-emulator: Could not get the TPM established flag: %s" , |
405 | strerror(errno)); |
406 | return false; |
407 | } |
408 | trace_tpm_emulator_get_tpm_established_flag(est.u.resp.bit); |
409 | |
410 | tpm_emu->established_flag_cached = 1; |
411 | tpm_emu->established_flag = (est.u.resp.bit != 0); |
412 | |
413 | return tpm_emu->established_flag; |
414 | } |
415 | |
416 | static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb, |
417 | uint8_t locty) |
418 | { |
419 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
420 | ptm_reset_est reset_est; |
421 | ptm_res res; |
422 | |
423 | /* only a TPM 2.0 will support this */ |
424 | if (tpm_emu->tpm_version != TPM_VERSION_2_0) { |
425 | return 0; |
426 | } |
427 | |
428 | reset_est.u.req.loc = tpm_emu->cur_locty_number; |
429 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED, |
430 | &reset_est, sizeof(reset_est), |
431 | sizeof(reset_est)) < 0) { |
432 | error_report("tpm-emulator: Could not reset the establishment bit: %s" , |
433 | strerror(errno)); |
434 | return -1; |
435 | } |
436 | |
437 | res = be32_to_cpu(reset_est.u.resp.tpm_result); |
438 | if (res) { |
439 | error_report( |
440 | "tpm-emulator: TPM result for rest established flag: 0x%x %s" , |
441 | res, tpm_emulator_strerror(res)); |
442 | return -1; |
443 | } |
444 | |
445 | tpm_emu->established_flag_cached = 0; |
446 | |
447 | return 0; |
448 | } |
449 | |
450 | static void tpm_emulator_cancel_cmd(TPMBackend *tb) |
451 | { |
452 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
453 | ptm_res res; |
454 | |
455 | if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) { |
456 | trace_tpm_emulator_cancel_cmd_not_supt(); |
457 | return; |
458 | } |
459 | |
460 | /* FIXME: make the function non-blocking, or it may block a VCPU */ |
461 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0, |
462 | sizeof(res)) < 0) { |
463 | error_report("tpm-emulator: Could not cancel command: %s" , |
464 | strerror(errno)); |
465 | } else if (res != 0) { |
466 | error_report("tpm-emulator: Failed to cancel TPM: 0x%x" , |
467 | be32_to_cpu(res)); |
468 | } |
469 | } |
470 | |
471 | static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb) |
472 | { |
473 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
474 | |
475 | return tpm_emu->tpm_version; |
476 | } |
477 | |
478 | static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) |
479 | { |
480 | size_t actual_size; |
481 | |
482 | if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) { |
483 | return 4096; |
484 | } |
485 | |
486 | return actual_size; |
487 | } |
488 | |
489 | static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) |
490 | { |
491 | Error *err = NULL; |
492 | ptm_cap caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB | |
493 | PTM_CAP_STOP; |
494 | |
495 | if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) { |
496 | error_setg(&tpm_emu->migration_blocker, |
497 | "Migration disabled: TPM emulator does not support " |
498 | "migration" ); |
499 | migrate_add_blocker(tpm_emu->migration_blocker, &err); |
500 | if (err) { |
501 | error_report_err(err); |
502 | error_free(tpm_emu->migration_blocker); |
503 | tpm_emu->migration_blocker = NULL; |
504 | |
505 | return -1; |
506 | } |
507 | } |
508 | |
509 | return 0; |
510 | } |
511 | |
512 | static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu) |
513 | { |
514 | ptm_res res; |
515 | Error *err = NULL; |
516 | int fds[2] = { -1, -1 }; |
517 | |
518 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { |
519 | error_report("tpm-emulator: Failed to create socketpair" ); |
520 | return -1; |
521 | } |
522 | |
523 | qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1); |
524 | |
525 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0, |
526 | sizeof(res)) < 0 || res != 0) { |
527 | error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s" , |
528 | strerror(errno)); |
529 | goto err_exit; |
530 | } |
531 | |
532 | tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err)); |
533 | if (err) { |
534 | error_prepend(&err, "tpm-emulator: Failed to create io channel: " ); |
535 | error_report_err(err); |
536 | goto err_exit; |
537 | } |
538 | |
539 | closesocket(fds[1]); |
540 | |
541 | return 0; |
542 | |
543 | err_exit: |
544 | closesocket(fds[0]); |
545 | closesocket(fds[1]); |
546 | return -1; |
547 | } |
548 | |
549 | static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) |
550 | { |
551 | const char *value; |
552 | |
553 | value = qemu_opt_get(opts, "chardev" ); |
554 | if (value) { |
555 | Error *err = NULL; |
556 | Chardev *dev = qemu_chr_find(value); |
557 | |
558 | if (!dev) { |
559 | error_report("tpm-emulator: tpm chardev '%s' not found." , value); |
560 | goto err; |
561 | } |
562 | |
563 | if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { |
564 | error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':" , |
565 | value); |
566 | error_report_err(err); |
567 | goto err; |
568 | } |
569 | |
570 | tpm_emu->options->chardev = g_strdup(value); |
571 | } |
572 | |
573 | if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { |
574 | goto err; |
575 | } |
576 | |
577 | /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used |
578 | * by passthrough driver, which not yet using GIOChannel. |
579 | */ |
580 | if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd, |
581 | &tpm_emu->tpm_version)) { |
582 | error_report("'%s' is not emulating TPM device. Error: %s" , |
583 | tpm_emu->options->chardev, strerror(errno)); |
584 | goto err; |
585 | } |
586 | |
587 | switch (tpm_emu->tpm_version) { |
588 | case TPM_VERSION_1_2: |
589 | trace_tpm_emulator_handle_device_opts_tpm12(); |
590 | break; |
591 | case TPM_VERSION_2_0: |
592 | trace_tpm_emulator_handle_device_opts_tpm2(); |
593 | break; |
594 | default: |
595 | trace_tpm_emulator_handle_device_opts_unspec(); |
596 | } |
597 | |
598 | if (tpm_emulator_probe_caps(tpm_emu) || |
599 | tpm_emulator_check_caps(tpm_emu)) { |
600 | goto err; |
601 | } |
602 | |
603 | return tpm_emulator_block_migration(tpm_emu); |
604 | |
605 | err: |
606 | trace_tpm_emulator_handle_device_opts_startup_error(); |
607 | |
608 | return -1; |
609 | } |
610 | |
611 | static TPMBackend *tpm_emulator_create(QemuOpts *opts) |
612 | { |
613 | TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); |
614 | |
615 | if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) { |
616 | object_unref(OBJECT(tb)); |
617 | return NULL; |
618 | } |
619 | |
620 | return tb; |
621 | } |
622 | |
623 | static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) |
624 | { |
625 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
626 | TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); |
627 | |
628 | options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR; |
629 | options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options); |
630 | |
631 | return options; |
632 | } |
633 | |
634 | static const QemuOptDesc tpm_emulator_cmdline_opts[] = { |
635 | TPM_STANDARD_CMDLINE_OPTS, |
636 | { |
637 | .name = "chardev" , |
638 | .type = QEMU_OPT_STRING, |
639 | .help = "Character device to use for out-of-band control messages" , |
640 | }, |
641 | { /* end of list */ }, |
642 | }; |
643 | |
644 | /* |
645 | * Transfer a TPM state blob from the TPM into a provided buffer. |
646 | * |
647 | * @tpm_emu: TPMEmulator |
648 | * @type: the type of blob to transfer |
649 | * @tsb: the TPMSizeBuffer to fill with the blob |
650 | * @flags: the flags to return to the caller |
651 | */ |
652 | static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu, |
653 | uint8_t type, |
654 | TPMSizedBuffer *tsb, |
655 | uint32_t *flags) |
656 | { |
657 | ptm_getstate pgs; |
658 | ptm_res res; |
659 | ssize_t n; |
660 | uint32_t totlength, length; |
661 | |
662 | tpm_sized_buffer_reset(tsb); |
663 | |
664 | pgs.u.req.state_flags = cpu_to_be32(PTM_STATE_FLAG_DECRYPTED); |
665 | pgs.u.req.type = cpu_to_be32(type); |
666 | pgs.u.req.offset = 0; |
667 | |
668 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB, |
669 | &pgs, sizeof(pgs.u.req), |
670 | offsetof(ptm_getstate, u.resp.data)) < 0) { |
671 | error_report("tpm-emulator: could not get state blob type %d : %s" , |
672 | type, strerror(errno)); |
673 | return -1; |
674 | } |
675 | |
676 | res = be32_to_cpu(pgs.u.resp.tpm_result); |
677 | if (res != 0 && (res & 0x800) == 0) { |
678 | error_report("tpm-emulator: Getting the stateblob (type %d) failed " |
679 | "with a TPM error 0x%x %s" , type, res, |
680 | tpm_emulator_strerror(res)); |
681 | return -1; |
682 | } |
683 | |
684 | totlength = be32_to_cpu(pgs.u.resp.totlength); |
685 | length = be32_to_cpu(pgs.u.resp.length); |
686 | if (totlength != length) { |
687 | error_report("tpm-emulator: Expecting to read %u bytes " |
688 | "but would get %u" , totlength, length); |
689 | return -1; |
690 | } |
691 | |
692 | *flags = be32_to_cpu(pgs.u.resp.state_flags); |
693 | |
694 | if (totlength > 0) { |
695 | tsb->buffer = g_try_malloc(totlength); |
696 | if (!tsb->buffer) { |
697 | error_report("tpm-emulator: Out of memory allocating %u bytes" , |
698 | totlength); |
699 | return -1; |
700 | } |
701 | |
702 | n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, tsb->buffer, totlength); |
703 | if (n != totlength) { |
704 | error_report("tpm-emulator: Could not read stateblob (type %d); " |
705 | "expected %u bytes, got %zd" , |
706 | type, totlength, n); |
707 | return -1; |
708 | } |
709 | } |
710 | tsb->size = totlength; |
711 | |
712 | trace_tpm_emulator_get_state_blob(type, tsb->size, *flags); |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu) |
718 | { |
719 | TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; |
720 | |
721 | if (tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT, |
722 | &state_blobs->permanent, |
723 | &state_blobs->permanent_flags) < 0 || |
724 | tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE, |
725 | &state_blobs->volatil, |
726 | &state_blobs->volatil_flags) < 0 || |
727 | tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE, |
728 | &state_blobs->savestate, |
729 | &state_blobs->savestate_flags) < 0) { |
730 | goto err_exit; |
731 | } |
732 | |
733 | return 0; |
734 | |
735 | err_exit: |
736 | tpm_sized_buffer_reset(&state_blobs->volatil); |
737 | tpm_sized_buffer_reset(&state_blobs->permanent); |
738 | tpm_sized_buffer_reset(&state_blobs->savestate); |
739 | |
740 | return -1; |
741 | } |
742 | |
743 | /* |
744 | * Transfer a TPM state blob to the TPM emulator. |
745 | * |
746 | * @tpm_emu: TPMEmulator |
747 | * @type: the type of TPM state blob to transfer |
748 | * @tsb: TPMSizedBuffer containing the TPM state blob |
749 | * @flags: Flags describing the (encryption) state of the TPM state blob |
750 | */ |
751 | static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu, |
752 | uint32_t type, |
753 | TPMSizedBuffer *tsb, |
754 | uint32_t flags) |
755 | { |
756 | ssize_t n; |
757 | ptm_setstate pss; |
758 | ptm_res tpm_result; |
759 | |
760 | if (tsb->size == 0) { |
761 | return 0; |
762 | } |
763 | |
764 | pss = (ptm_setstate) { |
765 | .u.req.state_flags = cpu_to_be32(flags), |
766 | .u.req.type = cpu_to_be32(type), |
767 | .u.req.length = cpu_to_be32(tsb->size), |
768 | }; |
769 | |
770 | /* write the header only */ |
771 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss, |
772 | offsetof(ptm_setstate, u.req.data), 0) < 0) { |
773 | error_report("tpm-emulator: could not set state blob type %d : %s" , |
774 | type, strerror(errno)); |
775 | return -1; |
776 | } |
777 | |
778 | /* now the body */ |
779 | n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size); |
780 | if (n != tsb->size) { |
781 | error_report("tpm-emulator: Writing the stateblob (type %d) " |
782 | "failed; could not write %u bytes, but only %zd" , |
783 | type, tsb->size, n); |
784 | return -1; |
785 | } |
786 | |
787 | /* now get the result */ |
788 | n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, |
789 | (uint8_t *)&pss, sizeof(pss.u.resp)); |
790 | if (n != sizeof(pss.u.resp)) { |
791 | error_report("tpm-emulator: Reading response from writing stateblob " |
792 | "(type %d) failed; expected %zu bytes, got %zd" , type, |
793 | sizeof(pss.u.resp), n); |
794 | return -1; |
795 | } |
796 | |
797 | tpm_result = be32_to_cpu(pss.u.resp.tpm_result); |
798 | if (tpm_result != 0) { |
799 | error_report("tpm-emulator: Setting the stateblob (type %d) failed " |
800 | "with a TPM error 0x%x %s" , type, tpm_result, |
801 | tpm_emulator_strerror(tpm_result)); |
802 | return -1; |
803 | } |
804 | |
805 | trace_tpm_emulator_set_state_blob(type, tsb->size, flags); |
806 | |
807 | return 0; |
808 | } |
809 | |
810 | /* |
811 | * Set all the TPM state blobs. |
812 | * |
813 | * Returns a negative errno code in case of error. |
814 | */ |
815 | static int tpm_emulator_set_state_blobs(TPMBackend *tb) |
816 | { |
817 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
818 | TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; |
819 | |
820 | trace_tpm_emulator_set_state_blobs(); |
821 | |
822 | if (tpm_emulator_stop_tpm(tb) < 0) { |
823 | trace_tpm_emulator_set_state_blobs_error("Could not stop TPM" ); |
824 | return -EIO; |
825 | } |
826 | |
827 | if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT, |
828 | &state_blobs->permanent, |
829 | state_blobs->permanent_flags) < 0 || |
830 | tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE, |
831 | &state_blobs->volatil, |
832 | state_blobs->volatil_flags) < 0 || |
833 | tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE, |
834 | &state_blobs->savestate, |
835 | state_blobs->savestate_flags) < 0) { |
836 | return -EIO; |
837 | } |
838 | |
839 | trace_tpm_emulator_set_state_blobs_done(); |
840 | |
841 | return 0; |
842 | } |
843 | |
844 | static int tpm_emulator_pre_save(void *opaque) |
845 | { |
846 | TPMBackend *tb = opaque; |
847 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); |
848 | |
849 | trace_tpm_emulator_pre_save(); |
850 | |
851 | tpm_backend_finish_sync(tb); |
852 | |
853 | /* get the state blobs from the TPM */ |
854 | return tpm_emulator_get_state_blobs(tpm_emu); |
855 | } |
856 | |
857 | /* |
858 | * Load the TPM state blobs into the TPM. |
859 | * |
860 | * Returns negative errno codes in case of error. |
861 | */ |
862 | static int tpm_emulator_post_load(void *opaque, int version_id) |
863 | { |
864 | TPMBackend *tb = opaque; |
865 | int ret; |
866 | |
867 | ret = tpm_emulator_set_state_blobs(tb); |
868 | if (ret < 0) { |
869 | return ret; |
870 | } |
871 | |
872 | if (tpm_emulator_startup_tpm_resume(tb, 0, true) < 0) { |
873 | return -EIO; |
874 | } |
875 | |
876 | return 0; |
877 | } |
878 | |
879 | static const VMStateDescription vmstate_tpm_emulator = { |
880 | .name = "tpm-emulator" , |
881 | .version_id = 0, |
882 | .pre_save = tpm_emulator_pre_save, |
883 | .post_load = tpm_emulator_post_load, |
884 | .fields = (VMStateField[]) { |
885 | VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator), |
886 | VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator), |
887 | VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.permanent.buffer, |
888 | TPMEmulator, 0, 0, |
889 | state_blobs.permanent.size), |
890 | |
891 | VMSTATE_UINT32(state_blobs.volatil_flags, TPMEmulator), |
892 | VMSTATE_UINT32(state_blobs.volatil.size, TPMEmulator), |
893 | VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.volatil.buffer, |
894 | TPMEmulator, 0, 0, |
895 | state_blobs.volatil.size), |
896 | |
897 | VMSTATE_UINT32(state_blobs.savestate_flags, TPMEmulator), |
898 | VMSTATE_UINT32(state_blobs.savestate.size, TPMEmulator), |
899 | VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.savestate.buffer, |
900 | TPMEmulator, 0, 0, |
901 | state_blobs.savestate.size), |
902 | |
903 | VMSTATE_END_OF_LIST() |
904 | } |
905 | }; |
906 | |
907 | static void tpm_emulator_inst_init(Object *obj) |
908 | { |
909 | TPMEmulator *tpm_emu = TPM_EMULATOR(obj); |
910 | |
911 | trace_tpm_emulator_inst_init(); |
912 | |
913 | tpm_emu->options = g_new0(TPMEmulatorOptions, 1); |
914 | tpm_emu->cur_locty_number = ~0; |
915 | qemu_mutex_init(&tpm_emu->mutex); |
916 | |
917 | vmstate_register(NULL, -1, &vmstate_tpm_emulator, obj); |
918 | } |
919 | |
920 | /* |
921 | * Gracefully shut down the external TPM |
922 | */ |
923 | static void tpm_emulator_shutdown(TPMEmulator *tpm_emu) |
924 | { |
925 | ptm_res res; |
926 | |
927 | if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) { |
928 | error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s" , |
929 | strerror(errno)); |
930 | } else if (res != 0) { |
931 | error_report("tpm-emulator: TPM result for shutdown: 0x%x %s" , |
932 | be32_to_cpu(res), tpm_emulator_strerror(be32_to_cpu(res))); |
933 | } |
934 | } |
935 | |
936 | static void tpm_emulator_inst_finalize(Object *obj) |
937 | { |
938 | TPMEmulator *tpm_emu = TPM_EMULATOR(obj); |
939 | TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; |
940 | |
941 | tpm_emulator_shutdown(tpm_emu); |
942 | |
943 | object_unref(OBJECT(tpm_emu->data_ioc)); |
944 | |
945 | qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false); |
946 | |
947 | qapi_free_TPMEmulatorOptions(tpm_emu->options); |
948 | |
949 | if (tpm_emu->migration_blocker) { |
950 | migrate_del_blocker(tpm_emu->migration_blocker); |
951 | error_free(tpm_emu->migration_blocker); |
952 | } |
953 | |
954 | tpm_sized_buffer_reset(&state_blobs->volatil); |
955 | tpm_sized_buffer_reset(&state_blobs->permanent); |
956 | tpm_sized_buffer_reset(&state_blobs->savestate); |
957 | |
958 | qemu_mutex_destroy(&tpm_emu->mutex); |
959 | |
960 | vmstate_unregister(NULL, &vmstate_tpm_emulator, obj); |
961 | } |
962 | |
963 | static void tpm_emulator_class_init(ObjectClass *klass, void *data) |
964 | { |
965 | TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); |
966 | |
967 | tbc->type = TPM_TYPE_EMULATOR; |
968 | tbc->opts = tpm_emulator_cmdline_opts; |
969 | tbc->desc = "TPM emulator backend driver" ; |
970 | tbc->create = tpm_emulator_create; |
971 | tbc->startup_tpm = tpm_emulator_startup_tpm; |
972 | tbc->cancel_cmd = tpm_emulator_cancel_cmd; |
973 | tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag; |
974 | tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag; |
975 | tbc->get_tpm_version = tpm_emulator_get_tpm_version; |
976 | tbc->get_buffer_size = tpm_emulator_get_buffer_size; |
977 | tbc->get_tpm_options = tpm_emulator_get_tpm_options; |
978 | |
979 | tbc->handle_request = tpm_emulator_handle_request; |
980 | } |
981 | |
982 | static const TypeInfo tpm_emulator_info = { |
983 | .name = TYPE_TPM_EMULATOR, |
984 | .parent = TYPE_TPM_BACKEND, |
985 | .instance_size = sizeof(TPMEmulator), |
986 | .class_init = tpm_emulator_class_init, |
987 | .instance_init = tpm_emulator_inst_init, |
988 | .instance_finalize = tpm_emulator_inst_finalize, |
989 | }; |
990 | |
991 | static void tpm_emulator_register(void) |
992 | { |
993 | type_register_static(&tpm_emulator_info); |
994 | } |
995 | |
996 | type_init(tpm_emulator_register) |
997 | |