1 /* 2 * passthrough TPM driver 3 * 4 * Copyright (c) 2010 - 2013 IBM Corporation 5 * Authors: 6 * Stefan Berger <stefanb@us.ibm.com> 7 * 8 * Copyright (C) 2011 IAIK, Graz University of Technology 9 * Author: Andreas Niederl 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Lesser General Public 13 * License as published by the Free Software Foundation; either 14 * version 2 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public 22 * License along with this library; if not, see <http://www.gnu.org/licenses/> 23 */ 24 25 #include <dirent.h> 26 27 #include "qemu-common.h" 28 #include "qapi/error.h" 29 #include "qemu/sockets.h" 30 #include "sysemu/tpm_backend.h" 31 #include "tpm_int.h" 32 #include "hw/hw.h" 33 #include "hw/i386/pc.h" 34 #include "sysemu/tpm_backend_int.h" 35 #include "tpm_tis.h" 36 37 /* #define DEBUG_TPM */ 38 39 #ifdef DEBUG_TPM 40 #define DPRINTF(fmt, ...) \ 41 do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) 42 #else 43 #define DPRINTF(fmt, ...) \ 44 do { } while (0) 45 #endif 46 47 #define TYPE_TPM_PASSTHROUGH "tpm-passthrough" 48 #define TPM_PASSTHROUGH(obj) \ 49 OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH) 50 51 static const TPMDriverOps tpm_passthrough_driver; 52 53 /* data structures */ 54 typedef struct TPMPassthruThreadParams { 55 TPMState *tpm_state; 56 57 TPMRecvDataCB *recv_data_callback; 58 TPMBackend *tb; 59 } TPMPassthruThreadParams; 60 61 struct TPMPassthruState { 62 TPMBackend parent; 63 64 TPMBackendThread tbt; 65 66 TPMPassthruThreadParams tpm_thread_params; 67 68 char *tpm_dev; 69 int tpm_fd; 70 bool tpm_executing; 71 bool tpm_op_canceled; 72 int cancel_fd; 73 bool had_startup_error; 74 }; 75 76 typedef struct TPMPassthruState TPMPassthruState; 77 78 #define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0" 79 80 /* functions */ 81 82 static void tpm_passthrough_cancel_cmd(TPMBackend *tb); 83 84 static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len) 85 { 86 return send_all(fd, buf, len); 87 } 88 89 static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len) 90 { 91 return recv_all(fd, buf, len, true); 92 } 93 94 static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf) 95 { 96 struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf; 97 98 return be32_to_cpu(resp->len); 99 } 100 101 /* 102 * Write an error message in the given output buffer. 103 */ 104 static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len) 105 { 106 if (out_len >= sizeof(struct tpm_resp_hdr)) { 107 struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out; 108 109 resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND); 110 resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr)); 111 resp->errcode = cpu_to_be32(TPM_FAIL); 112 } 113 } 114 115 static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len) 116 { 117 struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in; 118 119 if (in_len >= sizeof(*hdr)) { 120 return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest); 121 } 122 123 return false; 124 } 125 126 static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, 127 const uint8_t *in, uint32_t in_len, 128 uint8_t *out, uint32_t out_len, 129 bool *selftest_done) 130 { 131 int ret; 132 bool is_selftest; 133 const struct tpm_resp_hdr *hdr; 134 135 tpm_pt->tpm_op_canceled = false; 136 tpm_pt->tpm_executing = true; 137 *selftest_done = false; 138 139 is_selftest = tpm_passthrough_is_selftest(in, in_len); 140 141 ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len); 142 if (ret != in_len) { 143 if (!tpm_pt->tpm_op_canceled || 144 (tpm_pt->tpm_op_canceled && errno != ECANCELED)) { 145 error_report("tpm_passthrough: error while transmitting data " 146 "to TPM: %s (%i)", 147 strerror(errno), errno); 148 } 149 goto err_exit; 150 } 151 152 tpm_pt->tpm_executing = false; 153 154 ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len); 155 if (ret < 0) { 156 if (!tpm_pt->tpm_op_canceled || 157 (tpm_pt->tpm_op_canceled && errno != ECANCELED)) { 158 error_report("tpm_passthrough: error while reading data from " 159 "TPM: %s (%i)", 160 strerror(errno), errno); 161 } 162 } else if (ret < sizeof(struct tpm_resp_hdr) || 163 tpm_passthrough_get_size_from_buffer(out) != ret) { 164 ret = -1; 165 error_report("tpm_passthrough: received invalid response " 166 "packet from TPM"); 167 } 168 169 if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) { 170 hdr = (struct tpm_resp_hdr *)out; 171 *selftest_done = (be32_to_cpu(hdr->errcode) == 0); 172 } 173 174 err_exit: 175 if (ret < 0) { 176 tpm_write_fatal_error_response(out, out_len); 177 } 178 179 tpm_pt->tpm_executing = false; 180 181 return ret; 182 } 183 184 static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt, 185 const TPMLocality *locty_data, 186 bool *selftest_done) 187 { 188 return tpm_passthrough_unix_tx_bufs(tpm_pt, 189 locty_data->w_buffer.buffer, 190 locty_data->w_offset, 191 locty_data->r_buffer.buffer, 192 locty_data->r_buffer.size, 193 selftest_done); 194 } 195 196 static void tpm_passthrough_worker_thread(gpointer data, 197 gpointer user_data) 198 { 199 TPMPassthruThreadParams *thr_parms = user_data; 200 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb); 201 TPMBackendCmd cmd = (TPMBackendCmd)data; 202 bool selftest_done = false; 203 204 DPRINTF("tpm_passthrough: processing command type %d\n", cmd); 205 206 switch (cmd) { 207 case TPM_BACKEND_CMD_PROCESS_CMD: 208 tpm_passthrough_unix_transfer(tpm_pt, 209 thr_parms->tpm_state->locty_data, 210 &selftest_done); 211 212 thr_parms->recv_data_callback(thr_parms->tpm_state, 213 thr_parms->tpm_state->locty_number, 214 selftest_done); 215 break; 216 case TPM_BACKEND_CMD_INIT: 217 case TPM_BACKEND_CMD_END: 218 case TPM_BACKEND_CMD_TPM_RESET: 219 /* nothing to do */ 220 break; 221 } 222 } 223 224 /* 225 * Start the TPM (thread). If it had been started before, then terminate 226 * and start it again. 227 */ 228 static int tpm_passthrough_startup_tpm(TPMBackend *tb) 229 { 230 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 231 232 /* terminate a running TPM */ 233 tpm_backend_thread_end(&tpm_pt->tbt); 234 235 tpm_backend_thread_create(&tpm_pt->tbt, 236 tpm_passthrough_worker_thread, 237 &tpm_pt->tpm_thread_params); 238 239 return 0; 240 } 241 242 static void tpm_passthrough_reset(TPMBackend *tb) 243 { 244 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 245 246 DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n"); 247 248 tpm_passthrough_cancel_cmd(tb); 249 250 tpm_backend_thread_end(&tpm_pt->tbt); 251 252 tpm_pt->had_startup_error = false; 253 } 254 255 static int tpm_passthrough_init(TPMBackend *tb, TPMState *s, 256 TPMRecvDataCB *recv_data_cb) 257 { 258 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 259 260 tpm_pt->tpm_thread_params.tpm_state = s; 261 tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb; 262 tpm_pt->tpm_thread_params.tb = tb; 263 264 return 0; 265 } 266 267 static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) 268 { 269 return false; 270 } 271 272 static bool tpm_passthrough_get_startup_error(TPMBackend *tb) 273 { 274 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 275 276 return tpm_pt->had_startup_error; 277 } 278 279 static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb) 280 { 281 size_t wanted_size = 4096; /* Linux tpm.c buffer size */ 282 283 if (sb->size != wanted_size) { 284 sb->buffer = g_realloc(sb->buffer, wanted_size); 285 sb->size = wanted_size; 286 } 287 return sb->size; 288 } 289 290 static void tpm_passthrough_deliver_request(TPMBackend *tb) 291 { 292 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 293 294 tpm_backend_thread_deliver_request(&tpm_pt->tbt); 295 } 296 297 static void tpm_passthrough_cancel_cmd(TPMBackend *tb) 298 { 299 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 300 int n; 301 302 /* 303 * As of Linux 3.7 the tpm_tis driver does not properly cancel 304 * commands on all TPM manufacturers' TPMs. 305 * Only cancel if we're busy so we don't cancel someone else's 306 * command, e.g., a command executed on the host. 307 */ 308 if (tpm_pt->tpm_executing) { 309 if (tpm_pt->cancel_fd >= 0) { 310 n = write(tpm_pt->cancel_fd, "-", 1); 311 if (n != 1) { 312 error_report("Canceling TPM command failed: %s", 313 strerror(errno)); 314 } else { 315 tpm_pt->tpm_op_canceled = true; 316 } 317 } else { 318 error_report("Cannot cancel TPM command due to missing " 319 "TPM sysfs cancel entry"); 320 } 321 } 322 } 323 324 static const char *tpm_passthrough_create_desc(void) 325 { 326 return "Passthrough TPM backend driver"; 327 } 328 329 /* 330 * A basic test of a TPM device. We expect a well formatted response header 331 * (error response is fine) within one second. 332 */ 333 static int tpm_passthrough_test_tpmdev(int fd) 334 { 335 struct tpm_req_hdr req = { 336 .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), 337 .len = cpu_to_be32(sizeof(req)), 338 .ordinal = cpu_to_be32(TPM_ORD_GetTicks), 339 }; 340 struct tpm_resp_hdr *resp; 341 fd_set readfds; 342 int n; 343 struct timeval tv = { 344 .tv_sec = 1, 345 .tv_usec = 0, 346 }; 347 unsigned char buf[1024]; 348 349 n = write(fd, &req, sizeof(req)); 350 if (n < 0) { 351 return errno; 352 } 353 if (n != sizeof(req)) { 354 return EFAULT; 355 } 356 357 FD_ZERO(&readfds); 358 FD_SET(fd, &readfds); 359 360 /* wait for a second */ 361 n = select(fd + 1, &readfds, NULL, NULL, &tv); 362 if (n != 1) { 363 return errno; 364 } 365 366 n = read(fd, &buf, sizeof(buf)); 367 if (n < sizeof(struct tpm_resp_hdr)) { 368 return EFAULT; 369 } 370 371 resp = (struct tpm_resp_hdr *)buf; 372 /* check the header */ 373 if (be16_to_cpu(resp->tag) != TPM_TAG_RSP_COMMAND || 374 be32_to_cpu(resp->len) != n) { 375 return EBADMSG; 376 } 377 378 return 0; 379 } 380 381 /* 382 * Unless path or file descriptor set has been provided by user, 383 * determine the sysfs cancel file following kernel documentation 384 * in Documentation/ABI/stable/sysfs-class-tpm. 385 * From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel 386 */ 387 static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) 388 { 389 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 390 int fd = -1; 391 char *dev; 392 char path[PATH_MAX]; 393 394 if (tb->cancel_path) { 395 fd = qemu_open(tb->cancel_path, O_WRONLY); 396 if (fd < 0) { 397 error_report("Could not open TPM cancel path : %s", 398 strerror(errno)); 399 } 400 return fd; 401 } 402 403 dev = strrchr(tpm_pt->tpm_dev, '/'); 404 if (dev) { 405 dev++; 406 if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel", 407 dev) < sizeof(path)) { 408 fd = qemu_open(path, O_WRONLY); 409 if (fd >= 0) { 410 tb->cancel_path = g_strdup(path); 411 } else { 412 error_report("tpm_passthrough: Could not open TPM cancel " 413 "path %s : %s", path, strerror(errno)); 414 } 415 } 416 } else { 417 error_report("tpm_passthrough: Bad TPM device path %s", 418 tpm_pt->tpm_dev); 419 } 420 421 return fd; 422 } 423 424 static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) 425 { 426 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 427 const char *value; 428 429 value = qemu_opt_get(opts, "cancel-path"); 430 tb->cancel_path = g_strdup(value); 431 432 value = qemu_opt_get(opts, "path"); 433 if (!value) { 434 value = TPM_PASSTHROUGH_DEFAULT_DEVICE; 435 } 436 437 tpm_pt->tpm_dev = g_strdup(value); 438 439 tb->path = g_strdup(tpm_pt->tpm_dev); 440 441 tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR); 442 if (tpm_pt->tpm_fd < 0) { 443 error_report("Cannot access TPM device using '%s': %s", 444 tpm_pt->tpm_dev, strerror(errno)); 445 goto err_free_parameters; 446 } 447 448 if (tpm_passthrough_test_tpmdev(tpm_pt->tpm_fd)) { 449 error_report("'%s' is not a TPM device.", 450 tpm_pt->tpm_dev); 451 goto err_close_tpmdev; 452 } 453 454 return 0; 455 456 err_close_tpmdev: 457 qemu_close(tpm_pt->tpm_fd); 458 tpm_pt->tpm_fd = -1; 459 460 err_free_parameters: 461 g_free(tb->path); 462 tb->path = NULL; 463 464 g_free(tpm_pt->tpm_dev); 465 tpm_pt->tpm_dev = NULL; 466 467 return 1; 468 } 469 470 static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) 471 { 472 Object *obj = object_new(TYPE_TPM_PASSTHROUGH); 473 TPMBackend *tb = TPM_BACKEND(obj); 474 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 475 476 tb->id = g_strdup(id); 477 /* let frontend set the fe_model to proper value */ 478 tb->fe_model = -1; 479 480 tb->ops = &tpm_passthrough_driver; 481 482 if (tpm_passthrough_handle_device_opts(opts, tb)) { 483 goto err_exit; 484 } 485 486 tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb); 487 if (tpm_pt->cancel_fd < 0) { 488 goto err_exit; 489 } 490 491 return tb; 492 493 err_exit: 494 g_free(tb->id); 495 496 return NULL; 497 } 498 499 static void tpm_passthrough_destroy(TPMBackend *tb) 500 { 501 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 502 503 tpm_passthrough_cancel_cmd(tb); 504 505 tpm_backend_thread_end(&tpm_pt->tbt); 506 507 qemu_close(tpm_pt->tpm_fd); 508 qemu_close(tpm_pt->cancel_fd); 509 510 g_free(tb->id); 511 g_free(tb->path); 512 g_free(tb->cancel_path); 513 g_free(tpm_pt->tpm_dev); 514 } 515 516 static const QemuOptDesc tpm_passthrough_cmdline_opts[] = { 517 TPM_STANDARD_CMDLINE_OPTS, 518 { 519 .name = "cancel-path", 520 .type = QEMU_OPT_STRING, 521 .help = "Sysfs file entry for canceling TPM commands", 522 }, 523 { 524 .name = "path", 525 .type = QEMU_OPT_STRING, 526 .help = "Path to TPM device on the host", 527 }, 528 { /* end of list */ }, 529 }; 530 531 static const TPMDriverOps tpm_passthrough_driver = { 532 .type = TPM_TYPE_PASSTHROUGH, 533 .opts = tpm_passthrough_cmdline_opts, 534 .desc = tpm_passthrough_create_desc, 535 .create = tpm_passthrough_create, 536 .destroy = tpm_passthrough_destroy, 537 .init = tpm_passthrough_init, 538 .startup_tpm = tpm_passthrough_startup_tpm, 539 .realloc_buffer = tpm_passthrough_realloc_buffer, 540 .reset = tpm_passthrough_reset, 541 .had_startup_error = tpm_passthrough_get_startup_error, 542 .deliver_request = tpm_passthrough_deliver_request, 543 .cancel_cmd = tpm_passthrough_cancel_cmd, 544 .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, 545 }; 546 547 static void tpm_passthrough_inst_init(Object *obj) 548 { 549 } 550 551 static void tpm_passthrough_inst_finalize(Object *obj) 552 { 553 } 554 555 static void tpm_passthrough_class_init(ObjectClass *klass, void *data) 556 { 557 TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); 558 559 tbc->ops = &tpm_passthrough_driver; 560 } 561 562 static const TypeInfo tpm_passthrough_info = { 563 .name = TYPE_TPM_PASSTHROUGH, 564 .parent = TYPE_TPM_BACKEND, 565 .instance_size = sizeof(TPMPassthruState), 566 .class_init = tpm_passthrough_class_init, 567 .instance_init = tpm_passthrough_inst_init, 568 .instance_finalize = tpm_passthrough_inst_finalize, 569 }; 570 571 static void tpm_passthrough_register(void) 572 { 573 type_register_static(&tpm_passthrough_info); 574 tpm_register_driver(&tpm_passthrough_driver); 575 } 576 577 type_init(tpm_passthrough_register) 578