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 "backends/tpm.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 int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, 116 const uint8_t *in, uint32_t in_len, 117 uint8_t *out, uint32_t out_len) 118 { 119 int ret; 120 121 tpm_pt->tpm_op_canceled = false; 122 tpm_pt->tpm_executing = true; 123 124 ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len); 125 if (ret != in_len) { 126 if (!tpm_pt->tpm_op_canceled || 127 (tpm_pt->tpm_op_canceled && errno != ECANCELED)) { 128 error_report("tpm_passthrough: error while transmitting data " 129 "to TPM: %s (%i)\n", 130 strerror(errno), errno); 131 } 132 goto err_exit; 133 } 134 135 tpm_pt->tpm_executing = false; 136 137 ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len); 138 if (ret < 0) { 139 if (!tpm_pt->tpm_op_canceled || 140 (tpm_pt->tpm_op_canceled && errno != ECANCELED)) { 141 error_report("tpm_passthrough: error while reading data from " 142 "TPM: %s (%i)\n", 143 strerror(errno), errno); 144 } 145 } else if (ret < sizeof(struct tpm_resp_hdr) || 146 tpm_passthrough_get_size_from_buffer(out) != ret) { 147 ret = -1; 148 error_report("tpm_passthrough: received invalid response " 149 "packet from TPM\n"); 150 } 151 152 err_exit: 153 if (ret < 0) { 154 tpm_write_fatal_error_response(out, out_len); 155 } 156 157 tpm_pt->tpm_executing = false; 158 159 return ret; 160 } 161 162 static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt, 163 const TPMLocality *locty_data) 164 { 165 return tpm_passthrough_unix_tx_bufs(tpm_pt, 166 locty_data->w_buffer.buffer, 167 locty_data->w_offset, 168 locty_data->r_buffer.buffer, 169 locty_data->r_buffer.size); 170 } 171 172 static void tpm_passthrough_worker_thread(gpointer data, 173 gpointer user_data) 174 { 175 TPMPassthruThreadParams *thr_parms = user_data; 176 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb); 177 TPMBackendCmd cmd = (TPMBackendCmd)data; 178 179 DPRINTF("tpm_passthrough: processing command type %d\n", cmd); 180 181 switch (cmd) { 182 case TPM_BACKEND_CMD_PROCESS_CMD: 183 tpm_passthrough_unix_transfer(tpm_pt, 184 thr_parms->tpm_state->locty_data); 185 186 thr_parms->recv_data_callback(thr_parms->tpm_state, 187 thr_parms->tpm_state->locty_number); 188 break; 189 case TPM_BACKEND_CMD_INIT: 190 case TPM_BACKEND_CMD_END: 191 case TPM_BACKEND_CMD_TPM_RESET: 192 /* nothing to do */ 193 break; 194 } 195 } 196 197 /* 198 * Start the TPM (thread). If it had been started before, then terminate 199 * and start it again. 200 */ 201 static int tpm_passthrough_startup_tpm(TPMBackend *tb) 202 { 203 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 204 205 /* terminate a running TPM */ 206 tpm_backend_thread_end(&tpm_pt->tbt); 207 208 tpm_backend_thread_create(&tpm_pt->tbt, 209 tpm_passthrough_worker_thread, 210 &tpm_pt->tpm_thread_params); 211 212 return 0; 213 } 214 215 static void tpm_passthrough_reset(TPMBackend *tb) 216 { 217 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 218 219 DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n"); 220 221 tpm_passthrough_cancel_cmd(tb); 222 223 tpm_backend_thread_end(&tpm_pt->tbt); 224 225 tpm_pt->had_startup_error = false; 226 } 227 228 static int tpm_passthrough_init(TPMBackend *tb, TPMState *s, 229 TPMRecvDataCB *recv_data_cb) 230 { 231 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 232 233 tpm_pt->tpm_thread_params.tpm_state = s; 234 tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb; 235 tpm_pt->tpm_thread_params.tb = tb; 236 237 return 0; 238 } 239 240 static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) 241 { 242 return false; 243 } 244 245 static bool tpm_passthrough_get_startup_error(TPMBackend *tb) 246 { 247 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 248 249 return tpm_pt->had_startup_error; 250 } 251 252 static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb) 253 { 254 size_t wanted_size = 4096; /* Linux tpm.c buffer size */ 255 256 if (sb->size != wanted_size) { 257 sb->buffer = g_realloc(sb->buffer, wanted_size); 258 sb->size = wanted_size; 259 } 260 return sb->size; 261 } 262 263 static void tpm_passthrough_deliver_request(TPMBackend *tb) 264 { 265 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 266 267 tpm_backend_thread_deliver_request(&tpm_pt->tbt); 268 } 269 270 static void tpm_passthrough_cancel_cmd(TPMBackend *tb) 271 { 272 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 273 int n; 274 275 /* 276 * As of Linux 3.7 the tpm_tis driver does not properly cancel 277 * commands on all TPM manufacturers' TPMs. 278 * Only cancel if we're busy so we don't cancel someone else's 279 * command, e.g., a command executed on the host. 280 */ 281 if (tpm_pt->tpm_executing) { 282 if (tpm_pt->cancel_fd >= 0) { 283 n = write(tpm_pt->cancel_fd, "-", 1); 284 if (n != 1) { 285 error_report("Canceling TPM command failed: %s\n", 286 strerror(errno)); 287 } else { 288 tpm_pt->tpm_op_canceled = true; 289 } 290 } else { 291 error_report("Cannot cancel TPM command due to missing " 292 "TPM sysfs cancel entry"); 293 } 294 } 295 } 296 297 static const char *tpm_passthrough_create_desc(void) 298 { 299 return "Passthrough TPM backend driver"; 300 } 301 302 /* 303 * A basic test of a TPM device. We expect a well formatted response header 304 * (error response is fine) within one second. 305 */ 306 static int tpm_passthrough_test_tpmdev(int fd) 307 { 308 struct tpm_req_hdr req = { 309 .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), 310 .len = cpu_to_be32(sizeof(req)), 311 .ordinal = cpu_to_be32(TPM_ORD_GetTicks), 312 }; 313 struct tpm_resp_hdr *resp; 314 fd_set readfds; 315 int n; 316 struct timeval tv = { 317 .tv_sec = 1, 318 .tv_usec = 0, 319 }; 320 unsigned char buf[1024]; 321 322 n = write(fd, &req, sizeof(req)); 323 if (n < 0) { 324 return errno; 325 } 326 if (n != sizeof(req)) { 327 return EFAULT; 328 } 329 330 FD_ZERO(&readfds); 331 FD_SET(fd, &readfds); 332 333 /* wait for a second */ 334 n = select(fd + 1, &readfds, NULL, NULL, &tv); 335 if (n != 1) { 336 return errno; 337 } 338 339 n = read(fd, &buf, sizeof(buf)); 340 if (n < sizeof(struct tpm_resp_hdr)) { 341 return EFAULT; 342 } 343 344 resp = (struct tpm_resp_hdr *)buf; 345 /* check the header */ 346 if (be16_to_cpu(resp->tag) != TPM_TAG_RSP_COMMAND || 347 be32_to_cpu(resp->len) != n) { 348 return EBADMSG; 349 } 350 351 return 0; 352 } 353 354 /* 355 * Check whether the given base path, e.g., /sys/class/misc/tpm0/device, 356 * is the sysfs directory of a TPM. A TPM sysfs directory should be uniquely 357 * recognizable by the file entries 'pcrs' and 'cancel'. 358 * Upon success 'true' is returned and the basebath buffer has '/cancel' 359 * appended. 360 */ 361 static bool tpm_passthrough_check_sysfs_cancel(char *basepath, size_t bufsz) 362 { 363 char path[PATH_MAX]; 364 struct stat statbuf; 365 366 snprintf(path, sizeof(path), "%s/pcrs", basepath); 367 if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) { 368 return false; 369 } 370 371 snprintf(path, sizeof(path), "%s/cancel", basepath); 372 if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) { 373 return false; 374 } 375 376 strncpy(basepath, path, bufsz); 377 378 return true; 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 */ 386 static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) 387 { 388 int fd = -1; 389 unsigned int idx; 390 DIR *pnp_dir; 391 char path[PATH_MAX]; 392 struct dirent entry, *result; 393 int len; 394 395 if (tb->cancel_path) { 396 fd = qemu_open(tb->cancel_path, O_WRONLY); 397 if (fd < 0) { 398 error_report("Could not open TPM cancel path : %s", 399 strerror(errno)); 400 } 401 return fd; 402 } 403 404 snprintf(path, sizeof(path), "/sys/class/misc"); 405 pnp_dir = opendir(path); 406 if (pnp_dir != NULL) { 407 while (readdir_r(pnp_dir, &entry, &result) == 0 && 408 result != NULL) { 409 /* 410 * only allow /sys/class/misc/tpm%u type of paths 411 */ 412 if (sscanf(entry.d_name, "tpm%u%n", &idx, &len) < 1 || 413 len <= strlen("tpm") || 414 len != strlen(entry.d_name)) { 415 continue; 416 } 417 418 snprintf(path, sizeof(path), "/sys/class/misc/%s/device", 419 entry.d_name); 420 if (!tpm_passthrough_check_sysfs_cancel(path, sizeof(path))) { 421 continue; 422 } 423 424 fd = qemu_open(path, O_WRONLY); 425 break; 426 } 427 closedir(pnp_dir); 428 } 429 430 if (fd >= 0) { 431 tb->cancel_path = g_strdup(path); 432 } 433 434 return fd; 435 } 436 437 static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) 438 { 439 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 440 const char *value; 441 442 value = qemu_opt_get(opts, "cancel-path"); 443 if (value) { 444 tb->cancel_path = g_strdup(value); 445 } 446 447 value = qemu_opt_get(opts, "path"); 448 if (!value) { 449 value = TPM_PASSTHROUGH_DEFAULT_DEVICE; 450 } 451 452 tpm_pt->tpm_dev = g_strdup(value); 453 454 tb->path = g_strdup(tpm_pt->tpm_dev); 455 456 tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR); 457 if (tpm_pt->tpm_fd < 0) { 458 error_report("Cannot access TPM device using '%s': %s\n", 459 tpm_pt->tpm_dev, strerror(errno)); 460 goto err_free_parameters; 461 } 462 463 if (tpm_passthrough_test_tpmdev(tpm_pt->tpm_fd)) { 464 error_report("'%s' is not a TPM device.\n", 465 tpm_pt->tpm_dev); 466 goto err_close_tpmdev; 467 } 468 469 return 0; 470 471 err_close_tpmdev: 472 qemu_close(tpm_pt->tpm_fd); 473 tpm_pt->tpm_fd = -1; 474 475 err_free_parameters: 476 g_free(tb->path); 477 tb->path = NULL; 478 479 g_free(tpm_pt->tpm_dev); 480 tpm_pt->tpm_dev = NULL; 481 482 return 1; 483 } 484 485 static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) 486 { 487 Object *obj = object_new(TYPE_TPM_PASSTHROUGH); 488 TPMBackend *tb = TPM_BACKEND(obj); 489 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 490 491 tb->id = g_strdup(id); 492 /* let frontend set the fe_model to proper value */ 493 tb->fe_model = -1; 494 495 tb->ops = &tpm_passthrough_driver; 496 497 if (tpm_passthrough_handle_device_opts(opts, tb)) { 498 goto err_exit; 499 } 500 501 tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb); 502 if (tpm_pt->cancel_fd < 0) { 503 goto err_exit; 504 } 505 506 return tb; 507 508 err_exit: 509 g_free(tb->id); 510 511 return NULL; 512 } 513 514 static void tpm_passthrough_destroy(TPMBackend *tb) 515 { 516 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 517 518 tpm_passthrough_cancel_cmd(tb); 519 520 tpm_backend_thread_end(&tpm_pt->tbt); 521 522 qemu_close(tpm_pt->tpm_fd); 523 qemu_close(tpm_pt->cancel_fd); 524 525 g_free(tb->id); 526 g_free(tb->path); 527 g_free(tb->cancel_path); 528 g_free(tpm_pt->tpm_dev); 529 } 530 531 static const TPMDriverOps tpm_passthrough_driver = { 532 .type = TPM_TYPE_PASSTHROUGH, 533 .desc = tpm_passthrough_create_desc, 534 .create = tpm_passthrough_create, 535 .destroy = tpm_passthrough_destroy, 536 .init = tpm_passthrough_init, 537 .startup_tpm = tpm_passthrough_startup_tpm, 538 .realloc_buffer = tpm_passthrough_realloc_buffer, 539 .reset = tpm_passthrough_reset, 540 .had_startup_error = tpm_passthrough_get_startup_error, 541 .deliver_request = tpm_passthrough_deliver_request, 542 .cancel_cmd = tpm_passthrough_cancel_cmd, 543 .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, 544 }; 545 546 static void tpm_passthrough_inst_init(Object *obj) 547 { 548 } 549 550 static void tpm_passthrough_inst_finalize(Object *obj) 551 { 552 } 553 554 static void tpm_passthrough_class_init(ObjectClass *klass, void *data) 555 { 556 TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); 557 558 tbc->ops = &tpm_passthrough_driver; 559 } 560 561 static const TypeInfo tpm_passthrough_info = { 562 .name = TYPE_TPM_PASSTHROUGH, 563 .parent = TYPE_TPM_BACKEND, 564 .instance_size = sizeof(TPMPassthruState), 565 .class_init = tpm_passthrough_class_init, 566 .instance_init = tpm_passthrough_inst_init, 567 .instance_finalize = tpm_passthrough_inst_finalize, 568 }; 569 570 static void tpm_passthrough_register(void) 571 { 572 type_register_static(&tpm_passthrough_info); 573 tpm_register_driver(&tpm_passthrough_driver); 574 } 575 576 type_init(tpm_passthrough_register) 577