1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2016 Intel Corporation 4 * 5 * Authors: 6 * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> 7 * 8 * Maintained by: <tpmdd-devel@lists.sourceforge.net> 9 * 10 * This file contains TPM2 protocol implementations of the commands 11 * used by the kernel internally. 12 */ 13 14 #include <linux/gfp.h> 15 #include <linux/unaligned.h> 16 #include "tpm.h" 17 18 enum tpm2_handle_types { 19 TPM2_HT_HMAC_SESSION = 0x02000000, 20 TPM2_HT_POLICY_SESSION = 0x03000000, 21 TPM2_HT_TRANSIENT = 0x80000000, 22 }; 23 24 struct tpm2_context { 25 __be64 sequence; 26 __be32 saved_handle; 27 __be32 hierarchy; 28 __be16 blob_size; 29 } __packed; 30 31 static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) 32 { 33 int i; 34 35 for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { 36 if (space->session_tbl[i]) 37 tpm2_flush_context(chip, space->session_tbl[i]); 38 } 39 } 40 41 int tpm2_init_space(struct tpm_space *space, unsigned int buf_size) 42 { 43 space->context_buf = kzalloc(buf_size, GFP_KERNEL); 44 if (!space->context_buf) 45 return -ENOMEM; 46 47 space->session_buf = kzalloc(buf_size, GFP_KERNEL); 48 if (space->session_buf == NULL) { 49 kfree(space->context_buf); 50 /* Prevent caller getting a dangling pointer. */ 51 space->context_buf = NULL; 52 return -ENOMEM; 53 } 54 55 space->buf_size = buf_size; 56 return 0; 57 } 58 59 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) 60 { 61 62 if (tpm_try_get_ops(chip) == 0) { 63 tpm2_flush_sessions(chip, space); 64 tpm_put_ops(chip); 65 } 66 67 kfree(space->context_buf); 68 kfree(space->session_buf); 69 } 70 71 int tpm2_load_context(struct tpm_chip *chip, u8 *buf, 72 unsigned int *offset, u32 *handle) 73 { 74 struct tpm_buf tbuf; 75 struct tpm2_context *ctx; 76 unsigned int body_size; 77 int rc; 78 79 rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD); 80 if (rc) 81 return rc; 82 83 ctx = (struct tpm2_context *)&buf[*offset]; 84 body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size); 85 tpm_buf_append(&tbuf, &buf[*offset], body_size); 86 87 rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL); 88 if (rc < 0) { 89 dev_warn(&chip->dev, "%s: failed with a system error %d\n", 90 __func__, rc); 91 tpm_buf_destroy(&tbuf); 92 return -EFAULT; 93 } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE || 94 rc == TPM2_RC_REFERENCE_H0) { 95 /* 96 * TPM_RC_HANDLE means that the session context can't 97 * be loaded because of an internal counter mismatch 98 * that makes the TPM think there might have been a 99 * replay. This might happen if the context was saved 100 * and loaded outside the space. 101 * 102 * TPM_RC_REFERENCE_H0 means the session has been 103 * flushed outside the space 104 */ 105 *handle = 0; 106 tpm_buf_destroy(&tbuf); 107 return -ENOENT; 108 } else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) { 109 tpm_buf_destroy(&tbuf); 110 return -EINVAL; 111 } else if (rc > 0) { 112 dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", 113 __func__, rc); 114 tpm_buf_destroy(&tbuf); 115 return -EFAULT; 116 } 117 118 *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]); 119 *offset += body_size; 120 121 tpm_buf_destroy(&tbuf); 122 return 0; 123 } 124 125 int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, 126 unsigned int buf_size, unsigned int *offset) 127 { 128 struct tpm_buf tbuf; 129 unsigned int body_size; 130 int rc; 131 132 rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE); 133 if (rc) 134 return rc; 135 136 tpm_buf_append_u32(&tbuf, handle); 137 138 rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL); 139 if (rc < 0) { 140 dev_warn(&chip->dev, "%s: failed with a system error %d\n", 141 __func__, rc); 142 tpm_buf_destroy(&tbuf); 143 return -EFAULT; 144 } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) { 145 tpm_buf_destroy(&tbuf); 146 return -ENOENT; 147 } else if (rc) { 148 dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", 149 __func__, rc); 150 tpm_buf_destroy(&tbuf); 151 return -EFAULT; 152 } 153 154 body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE; 155 if ((*offset + body_size) > buf_size) { 156 dev_warn(&chip->dev, "%s: out of backing storage\n", __func__); 157 tpm_buf_destroy(&tbuf); 158 return -ENOMEM; 159 } 160 161 memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size); 162 *offset += body_size; 163 tpm_buf_destroy(&tbuf); 164 return 0; 165 } 166 167 void tpm2_flush_space(struct tpm_chip *chip) 168 { 169 struct tpm_space *space = &chip->work_space; 170 int i; 171 172 if (!space) 173 return; 174 175 for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) 176 if (space->context_tbl[i] && ~space->context_tbl[i]) 177 tpm2_flush_context(chip, space->context_tbl[i]); 178 179 tpm2_flush_sessions(chip, space); 180 } 181 182 static int tpm2_load_space(struct tpm_chip *chip) 183 { 184 struct tpm_space *space = &chip->work_space; 185 unsigned int offset; 186 int i; 187 int rc; 188 189 for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) { 190 if (!space->context_tbl[i]) 191 continue; 192 193 /* sanity check, should never happen */ 194 if (~space->context_tbl[i]) { 195 dev_err(&chip->dev, "context table is inconsistent"); 196 return -EFAULT; 197 } 198 199 rc = tpm2_load_context(chip, space->context_buf, &offset, 200 &space->context_tbl[i]); 201 if (rc) 202 return rc; 203 } 204 205 for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) { 206 u32 handle; 207 208 if (!space->session_tbl[i]) 209 continue; 210 211 rc = tpm2_load_context(chip, space->session_buf, 212 &offset, &handle); 213 if (rc == -ENOENT) { 214 /* load failed, just forget session */ 215 space->session_tbl[i] = 0; 216 } else if (rc) { 217 tpm2_flush_space(chip); 218 return rc; 219 } 220 if (handle != space->session_tbl[i]) { 221 dev_warn(&chip->dev, "session restored to wrong handle\n"); 222 tpm2_flush_space(chip); 223 return -EFAULT; 224 } 225 } 226 227 return 0; 228 } 229 230 static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle) 231 { 232 u32 vhandle = be32_to_cpup((__be32 *)handle); 233 u32 phandle; 234 int i; 235 236 i = 0xFFFFFF - (vhandle & 0xFFFFFF); 237 if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i]) 238 return false; 239 240 phandle = space->context_tbl[i]; 241 *((__be32 *)handle) = cpu_to_be32(phandle); 242 return true; 243 } 244 245 static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd) 246 { 247 struct tpm_space *space = &chip->work_space; 248 unsigned int nr_handles; 249 u32 attrs; 250 __be32 *handle; 251 int i; 252 253 i = tpm2_find_cc(chip, cc); 254 if (i < 0) 255 return -EINVAL; 256 257 attrs = chip->cc_attrs_tbl[i]; 258 nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0); 259 260 handle = (__be32 *)&cmd[TPM_HEADER_SIZE]; 261 for (i = 0; i < nr_handles; i++, handle++) { 262 if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) { 263 if (!tpm2_map_to_phandle(space, handle)) 264 return -EINVAL; 265 } 266 } 267 268 return 0; 269 } 270 271 static int tpm_find_and_validate_cc(struct tpm_chip *chip, 272 struct tpm_space *space, 273 const void *cmd, size_t len) 274 { 275 const struct tpm_header *header = (const void *)cmd; 276 int i; 277 u32 cc; 278 u32 attrs; 279 unsigned int nr_handles; 280 281 if (len < TPM_HEADER_SIZE || !chip->nr_commands) 282 return -EINVAL; 283 284 cc = be32_to_cpu(header->ordinal); 285 286 i = tpm2_find_cc(chip, cc); 287 if (i < 0) { 288 dev_dbg(&chip->dev, "0x%04X is an invalid command\n", 289 cc); 290 return -EOPNOTSUPP; 291 } 292 293 attrs = chip->cc_attrs_tbl[i]; 294 nr_handles = 295 4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0)); 296 if (len < TPM_HEADER_SIZE + 4 * nr_handles) 297 goto err_len; 298 299 return cc; 300 err_len: 301 dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__, 302 len); 303 return -EINVAL; 304 } 305 306 int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd, 307 size_t cmdsiz) 308 { 309 int rc; 310 int cc; 311 312 if (!space) 313 return 0; 314 315 cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz); 316 if (cc < 0) 317 return cc; 318 319 memcpy(&chip->work_space.context_tbl, &space->context_tbl, 320 sizeof(space->context_tbl)); 321 memcpy(&chip->work_space.session_tbl, &space->session_tbl, 322 sizeof(space->session_tbl)); 323 memcpy(chip->work_space.context_buf, space->context_buf, 324 space->buf_size); 325 memcpy(chip->work_space.session_buf, space->session_buf, 326 space->buf_size); 327 328 rc = tpm2_load_space(chip); 329 if (rc) { 330 tpm2_flush_space(chip); 331 return rc; 332 } 333 334 rc = tpm2_map_command(chip, cc, cmd); 335 if (rc) { 336 tpm2_flush_space(chip); 337 return rc; 338 } 339 340 chip->last_cc = cc; 341 return 0; 342 } 343 344 static bool tpm2_add_session(struct tpm_chip *chip, u32 handle) 345 { 346 struct tpm_space *space = &chip->work_space; 347 int i; 348 349 for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) 350 if (space->session_tbl[i] == 0) 351 break; 352 353 if (i == ARRAY_SIZE(space->session_tbl)) 354 return false; 355 356 space->session_tbl[i] = handle; 357 return true; 358 } 359 360 static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc) 361 { 362 int i; 363 364 for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) { 365 if (alloc) { 366 if (!space->context_tbl[i]) { 367 space->context_tbl[i] = phandle; 368 break; 369 } 370 } else if (space->context_tbl[i] == phandle) 371 break; 372 } 373 374 if (i == ARRAY_SIZE(space->context_tbl)) 375 return 0; 376 377 return TPM2_HT_TRANSIENT | (0xFFFFFF - i); 378 } 379 380 static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, 381 size_t len) 382 { 383 struct tpm_space *space = &chip->work_space; 384 struct tpm_header *header = (struct tpm_header *)rsp; 385 u32 phandle; 386 u32 phandle_type; 387 u32 vhandle; 388 u32 attrs; 389 int i; 390 391 if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) 392 return 0; 393 394 i = tpm2_find_cc(chip, cc); 395 /* sanity check, should never happen */ 396 if (i < 0) 397 return -EFAULT; 398 399 attrs = chip->cc_attrs_tbl[i]; 400 if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1)) 401 return 0; 402 403 phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]); 404 phandle_type = phandle & 0xFF000000; 405 406 switch (phandle_type) { 407 case TPM2_HT_TRANSIENT: 408 vhandle = tpm2_map_to_vhandle(space, phandle, true); 409 if (!vhandle) 410 goto out_no_slots; 411 412 *(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle); 413 break; 414 case TPM2_HT_HMAC_SESSION: 415 case TPM2_HT_POLICY_SESSION: 416 if (!tpm2_add_session(chip, phandle)) 417 goto out_no_slots; 418 break; 419 default: 420 dev_err(&chip->dev, "%s: unknown handle 0x%08X\n", 421 __func__, phandle); 422 break; 423 } 424 425 return 0; 426 out_no_slots: 427 tpm2_flush_context(chip, phandle); 428 dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, 429 phandle); 430 return -ENOMEM; 431 } 432 433 struct tpm2_cap_handles { 434 u8 more_data; 435 __be32 capability; 436 __be32 count; 437 __be32 handles[]; 438 } __packed; 439 440 static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp, 441 size_t len) 442 { 443 struct tpm_space *space = &chip->work_space; 444 struct tpm_header *header = (struct tpm_header *)rsp; 445 struct tpm2_cap_handles *data; 446 u32 phandle; 447 u32 phandle_type; 448 u32 vhandle; 449 int i; 450 int j; 451 452 if (cc != TPM2_CC_GET_CAPABILITY || 453 be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) { 454 return 0; 455 } 456 457 if (len < TPM_HEADER_SIZE + 9) 458 return -EFAULT; 459 460 data = (void *)&rsp[TPM_HEADER_SIZE]; 461 if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES) 462 return 0; 463 464 if (be32_to_cpu(data->count) > (UINT_MAX - TPM_HEADER_SIZE - 9) / 4) 465 return -EFAULT; 466 467 if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count)) 468 return -EFAULT; 469 470 for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) { 471 phandle = be32_to_cpup((__be32 *)&data->handles[i]); 472 phandle_type = phandle & 0xFF000000; 473 474 switch (phandle_type) { 475 case TPM2_HT_TRANSIENT: 476 vhandle = tpm2_map_to_vhandle(space, phandle, false); 477 if (!vhandle) 478 break; 479 480 data->handles[j] = cpu_to_be32(vhandle); 481 j++; 482 break; 483 484 default: 485 data->handles[j] = cpu_to_be32(phandle); 486 j++; 487 break; 488 } 489 490 } 491 492 header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j); 493 data->count = cpu_to_be32(j); 494 return 0; 495 } 496 497 static int tpm2_save_space(struct tpm_chip *chip) 498 { 499 struct tpm_space *space = &chip->work_space; 500 unsigned int offset; 501 int i; 502 int rc; 503 504 for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) { 505 if (!(space->context_tbl[i] && ~space->context_tbl[i])) 506 continue; 507 508 rc = tpm2_save_context(chip, space->context_tbl[i], 509 space->context_buf, space->buf_size, 510 &offset); 511 if (rc == -ENOENT) { 512 space->context_tbl[i] = 0; 513 continue; 514 } else if (rc) 515 return rc; 516 517 tpm2_flush_context(chip, space->context_tbl[i]); 518 space->context_tbl[i] = ~0; 519 } 520 521 for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) { 522 if (!space->session_tbl[i]) 523 continue; 524 525 rc = tpm2_save_context(chip, space->session_tbl[i], 526 space->session_buf, space->buf_size, 527 &offset); 528 if (rc == -ENOENT) { 529 /* handle error saving session, just forget it */ 530 space->session_tbl[i] = 0; 531 } else if (rc < 0) { 532 tpm2_flush_space(chip); 533 return rc; 534 } 535 } 536 537 return 0; 538 } 539 540 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, 541 void *buf, size_t *bufsiz) 542 { 543 struct tpm_header *header = buf; 544 int rc; 545 546 if (!space) 547 return 0; 548 549 rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz); 550 if (rc) { 551 tpm2_flush_space(chip); 552 goto out; 553 } 554 555 rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz); 556 if (rc) { 557 tpm2_flush_space(chip); 558 goto out; 559 } 560 561 rc = tpm2_save_space(chip); 562 if (rc) { 563 tpm2_flush_space(chip); 564 goto out; 565 } 566 567 *bufsiz = be32_to_cpu(header->length); 568 569 memcpy(&space->context_tbl, &chip->work_space.context_tbl, 570 sizeof(space->context_tbl)); 571 memcpy(&space->session_tbl, &chip->work_space.session_tbl, 572 sizeof(space->session_tbl)); 573 memcpy(space->context_buf, chip->work_space.context_buf, 574 space->buf_size); 575 memcpy(space->session_buf, chip->work_space.session_buf, 576 space->buf_size); 577 578 return 0; 579 out: 580 dev_err(&chip->dev, "%s: error %d\n", __func__, rc); 581 return rc; 582 } 583 584 /* 585 * Put the reference to the main device. 586 */ 587 static void tpm_devs_release(struct device *dev) 588 { 589 struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); 590 591 /* release the master device reference */ 592 put_device(&chip->dev); 593 } 594 595 /* 596 * Remove the device file for exposed TPM spaces and release the device 597 * reference. This may also release the reference to the master device. 598 */ 599 void tpm_devs_remove(struct tpm_chip *chip) 600 { 601 cdev_device_del(&chip->cdevs, &chip->devs); 602 put_device(&chip->devs); 603 } 604 605 /* 606 * Add a device file to expose TPM spaces. Also take a reference to the 607 * main device. 608 */ 609 int tpm_devs_add(struct tpm_chip *chip) 610 { 611 int rc; 612 613 device_initialize(&chip->devs); 614 chip->devs.parent = chip->dev.parent; 615 chip->devs.class = &tpmrm_class; 616 617 /* 618 * Get extra reference on main device to hold on behalf of devs. 619 * This holds the chip structure while cdevs is in use. The 620 * corresponding put is in the tpm_devs_release. 621 */ 622 get_device(&chip->dev); 623 chip->devs.release = tpm_devs_release; 624 chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); 625 cdev_init(&chip->cdevs, &tpmrm_fops); 626 chip->cdevs.owner = THIS_MODULE; 627 628 rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); 629 if (rc) 630 goto err_put_devs; 631 632 rc = cdev_device_add(&chip->cdevs, &chip->devs); 633 if (rc) { 634 dev_err(&chip->devs, 635 "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", 636 dev_name(&chip->devs), MAJOR(chip->devs.devt), 637 MINOR(chip->devs.devt), rc); 638 goto err_put_devs; 639 } 640 641 return 0; 642 643 err_put_devs: 644 put_device(&chip->devs); 645 646 return rc; 647 } 648