1 /* 2 * Copyright (C) 2016 Intel Corporation 3 * 4 * Authors: 5 * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> 6 * 7 * Maintained by: <tpmdd-devel@lists.sourceforge.net> 8 * 9 * This file contains TPM2 protocol implementations of the commands 10 * used by the kernel internally. 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; version 2 15 * of the License. 16 */ 17 18 #include <linux/gfp.h> 19 #include <asm/unaligned.h> 20 #include "tpm.h" 21 22 enum tpm2_handle_types { 23 TPM2_HT_HMAC_SESSION = 0x02000000, 24 TPM2_HT_POLICY_SESSION = 0x03000000, 25 TPM2_HT_TRANSIENT = 0x80000000, 26 }; 27 28 struct tpm2_context { 29 __be64 sequence; 30 __be32 saved_handle; 31 __be32 hierarchy; 32 __be16 blob_size; 33 } __packed; 34 35 static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) 36 { 37 int i; 38 39 for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { 40 if (space->session_tbl[i]) 41 tpm2_flush_context_cmd(chip, space->session_tbl[i], 42 TPM_TRANSMIT_NESTED); 43 } 44 } 45 46 int tpm2_init_space(struct tpm_space *space) 47 { 48 space->context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 49 if (!space->context_buf) 50 return -ENOMEM; 51 52 space->session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 53 if (space->session_buf == NULL) { 54 kfree(space->context_buf); 55 return -ENOMEM; 56 } 57 58 return 0; 59 } 60 61 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) 62 { 63 mutex_lock(&chip->tpm_mutex); 64 tpm2_flush_sessions(chip, space); 65 mutex_unlock(&chip->tpm_mutex); 66 kfree(space->context_buf); 67 kfree(space->session_buf); 68 } 69 70 static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, 71 unsigned int *offset, u32 *handle) 72 { 73 struct tpm_buf tbuf; 74 struct tpm2_context *ctx; 75 unsigned int body_size; 76 int rc; 77 78 rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD); 79 if (rc) 80 return rc; 81 82 ctx = (struct tpm2_context *)&buf[*offset]; 83 body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size); 84 tpm_buf_append(&tbuf, &buf[*offset], body_size); 85 86 rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, 87 TPM_TRANSMIT_NESTED, 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 (rc > 0) { 109 dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", 110 __func__, rc); 111 tpm_buf_destroy(&tbuf); 112 return -EFAULT; 113 } 114 115 *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]); 116 *offset += body_size; 117 118 tpm_buf_destroy(&tbuf); 119 return 0; 120 } 121 122 static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, 123 unsigned int buf_size, unsigned int *offset) 124 { 125 struct tpm_buf tbuf; 126 unsigned int body_size; 127 int rc; 128 129 rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE); 130 if (rc) 131 return rc; 132 133 tpm_buf_append_u32(&tbuf, handle); 134 135 rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0, 136 TPM_TRANSMIT_NESTED, NULL); 137 if (rc < 0) { 138 dev_warn(&chip->dev, "%s: failed with a system error %d\n", 139 __func__, rc); 140 tpm_buf_destroy(&tbuf); 141 return -EFAULT; 142 } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) { 143 tpm_buf_destroy(&tbuf); 144 return -ENOENT; 145 } else if (rc) { 146 dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", 147 __func__, rc); 148 tpm_buf_destroy(&tbuf); 149 return -EFAULT; 150 } 151 152 body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE; 153 if ((*offset + body_size) > buf_size) { 154 dev_warn(&chip->dev, "%s: out of backing storage\n", __func__); 155 tpm_buf_destroy(&tbuf); 156 return -ENOMEM; 157 } 158 159 memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size); 160 *offset += body_size; 161 tpm_buf_destroy(&tbuf); 162 return 0; 163 } 164 165 static void tpm2_flush_space(struct tpm_chip *chip) 166 { 167 struct tpm_space *space = &chip->work_space; 168 int i; 169 170 for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) 171 if (space->context_tbl[i] && ~space->context_tbl[i]) 172 tpm2_flush_context_cmd(chip, space->context_tbl[i], 173 TPM_TRANSMIT_NESTED); 174 175 tpm2_flush_sessions(chip, space); 176 } 177 178 static int tpm2_load_space(struct tpm_chip *chip) 179 { 180 struct tpm_space *space = &chip->work_space; 181 unsigned int offset; 182 int i; 183 int rc; 184 185 for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) { 186 if (!space->context_tbl[i]) 187 continue; 188 189 /* sanity check, should never happen */ 190 if (~space->context_tbl[i]) { 191 dev_err(&chip->dev, "context table is inconsistent"); 192 return -EFAULT; 193 } 194 195 rc = tpm2_load_context(chip, space->context_buf, &offset, 196 &space->context_tbl[i]); 197 if (rc) 198 return rc; 199 } 200 201 for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) { 202 u32 handle; 203 204 if (!space->session_tbl[i]) 205 continue; 206 207 rc = tpm2_load_context(chip, space->session_buf, 208 &offset, &handle); 209 if (rc == -ENOENT) { 210 /* load failed, just forget session */ 211 space->session_tbl[i] = 0; 212 } else if (rc) { 213 tpm2_flush_space(chip); 214 return rc; 215 } 216 if (handle != space->session_tbl[i]) { 217 dev_warn(&chip->dev, "session restored to wrong handle\n"); 218 tpm2_flush_space(chip); 219 return -EFAULT; 220 } 221 } 222 223 return 0; 224 } 225 226 static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle) 227 { 228 u32 vhandle = be32_to_cpup((__be32 *)handle); 229 u32 phandle; 230 int i; 231 232 i = 0xFFFFFF - (vhandle & 0xFFFFFF); 233 if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i]) 234 return false; 235 236 phandle = space->context_tbl[i]; 237 *((__be32 *)handle) = cpu_to_be32(phandle); 238 return true; 239 } 240 241 static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd) 242 { 243 struct tpm_space *space = &chip->work_space; 244 unsigned int nr_handles; 245 u32 attrs; 246 __be32 *handle; 247 int i; 248 249 i = tpm2_find_cc(chip, cc); 250 if (i < 0) 251 return -EINVAL; 252 253 attrs = chip->cc_attrs_tbl[i]; 254 nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0); 255 256 handle = (__be32 *)&cmd[TPM_HEADER_SIZE]; 257 for (i = 0; i < nr_handles; i++, handle++) { 258 if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) { 259 if (!tpm2_map_to_phandle(space, handle)) 260 return -EINVAL; 261 } 262 } 263 264 return 0; 265 } 266 267 int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, 268 u8 *cmd) 269 { 270 int rc; 271 272 if (!space) 273 return 0; 274 275 memcpy(&chip->work_space.context_tbl, &space->context_tbl, 276 sizeof(space->context_tbl)); 277 memcpy(&chip->work_space.session_tbl, &space->session_tbl, 278 sizeof(space->session_tbl)); 279 memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE); 280 memcpy(chip->work_space.session_buf, space->session_buf, PAGE_SIZE); 281 282 rc = tpm2_load_space(chip); 283 if (rc) { 284 tpm2_flush_space(chip); 285 return rc; 286 } 287 288 rc = tpm2_map_command(chip, cc, cmd); 289 if (rc) { 290 tpm2_flush_space(chip); 291 return rc; 292 } 293 294 return 0; 295 } 296 297 static bool tpm2_add_session(struct tpm_chip *chip, u32 handle) 298 { 299 struct tpm_space *space = &chip->work_space; 300 int i; 301 302 for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) 303 if (space->session_tbl[i] == 0) 304 break; 305 306 if (i == ARRAY_SIZE(space->session_tbl)) 307 return false; 308 309 space->session_tbl[i] = handle; 310 return true; 311 } 312 313 static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc) 314 { 315 int i; 316 317 for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) { 318 if (alloc) { 319 if (!space->context_tbl[i]) { 320 space->context_tbl[i] = phandle; 321 break; 322 } 323 } else if (space->context_tbl[i] == phandle) 324 break; 325 } 326 327 if (i == ARRAY_SIZE(space->context_tbl)) 328 return 0; 329 330 return TPM2_HT_TRANSIENT | (0xFFFFFF - i); 331 } 332 333 static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, 334 size_t len) 335 { 336 struct tpm_space *space = &chip->work_space; 337 struct tpm_output_header *header = (void *)rsp; 338 u32 phandle; 339 u32 phandle_type; 340 u32 vhandle; 341 u32 attrs; 342 int i; 343 344 if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) 345 return 0; 346 347 i = tpm2_find_cc(chip, cc); 348 /* sanity check, should never happen */ 349 if (i < 0) 350 return -EFAULT; 351 352 attrs = chip->cc_attrs_tbl[i]; 353 if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1)) 354 return 0; 355 356 phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]); 357 phandle_type = phandle & 0xFF000000; 358 359 switch (phandle_type) { 360 case TPM2_HT_TRANSIENT: 361 vhandle = tpm2_map_to_vhandle(space, phandle, true); 362 if (!vhandle) 363 goto out_no_slots; 364 365 *(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle); 366 break; 367 case TPM2_HT_HMAC_SESSION: 368 case TPM2_HT_POLICY_SESSION: 369 if (!tpm2_add_session(chip, phandle)) 370 goto out_no_slots; 371 break; 372 default: 373 dev_err(&chip->dev, "%s: unknown handle 0x%08X\n", 374 __func__, phandle); 375 break; 376 } 377 378 return 0; 379 out_no_slots: 380 tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_NESTED); 381 dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, 382 phandle); 383 return -ENOMEM; 384 } 385 386 struct tpm2_cap_handles { 387 u8 more_data; 388 __be32 capability; 389 __be32 count; 390 __be32 handles[]; 391 } __packed; 392 393 static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp, 394 size_t len) 395 { 396 struct tpm_space *space = &chip->work_space; 397 struct tpm_output_header *header = (void *)rsp; 398 struct tpm2_cap_handles *data; 399 u32 phandle; 400 u32 phandle_type; 401 u32 vhandle; 402 int i; 403 int j; 404 405 if (cc != TPM2_CC_GET_CAPABILITY || 406 be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) { 407 return 0; 408 } 409 410 if (len < TPM_HEADER_SIZE + 9) 411 return -EFAULT; 412 413 data = (void *)&rsp[TPM_HEADER_SIZE]; 414 if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES) 415 return 0; 416 417 if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count)) 418 return -EFAULT; 419 420 for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) { 421 phandle = be32_to_cpup((__be32 *)&data->handles[i]); 422 phandle_type = phandle & 0xFF000000; 423 424 switch (phandle_type) { 425 case TPM2_HT_TRANSIENT: 426 vhandle = tpm2_map_to_vhandle(space, phandle, false); 427 if (!vhandle) 428 break; 429 430 data->handles[j] = cpu_to_be32(vhandle); 431 j++; 432 break; 433 434 default: 435 data->handles[j] = cpu_to_be32(phandle); 436 j++; 437 break; 438 } 439 440 } 441 442 header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j); 443 data->count = cpu_to_be32(j); 444 return 0; 445 } 446 447 static int tpm2_save_space(struct tpm_chip *chip) 448 { 449 struct tpm_space *space = &chip->work_space; 450 unsigned int offset; 451 int i; 452 int rc; 453 454 for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) { 455 if (!(space->context_tbl[i] && ~space->context_tbl[i])) 456 continue; 457 458 rc = tpm2_save_context(chip, space->context_tbl[i], 459 space->context_buf, PAGE_SIZE, 460 &offset); 461 if (rc == -ENOENT) { 462 space->context_tbl[i] = 0; 463 continue; 464 } else if (rc) 465 return rc; 466 467 tpm2_flush_context_cmd(chip, space->context_tbl[i], 468 TPM_TRANSMIT_NESTED); 469 space->context_tbl[i] = ~0; 470 } 471 472 for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) { 473 if (!space->session_tbl[i]) 474 continue; 475 476 rc = tpm2_save_context(chip, space->session_tbl[i], 477 space->session_buf, PAGE_SIZE, 478 &offset); 479 480 if (rc == -ENOENT) { 481 /* handle error saving session, just forget it */ 482 space->session_tbl[i] = 0; 483 } else if (rc < 0) { 484 tpm2_flush_space(chip); 485 return rc; 486 } 487 } 488 489 return 0; 490 } 491 492 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, 493 u32 cc, u8 *buf, size_t *bufsiz) 494 { 495 struct tpm_output_header *header = (void *)buf; 496 int rc; 497 498 if (!space) 499 return 0; 500 501 rc = tpm2_map_response_header(chip, cc, buf, *bufsiz); 502 if (rc) { 503 tpm2_flush_space(chip); 504 return rc; 505 } 506 507 rc = tpm2_map_response_body(chip, cc, buf, *bufsiz); 508 if (rc) { 509 tpm2_flush_space(chip); 510 return rc; 511 } 512 513 rc = tpm2_save_space(chip); 514 if (rc) { 515 tpm2_flush_space(chip); 516 return rc; 517 } 518 519 *bufsiz = be32_to_cpu(header->length); 520 521 memcpy(&space->context_tbl, &chip->work_space.context_tbl, 522 sizeof(space->context_tbl)); 523 memcpy(&space->session_tbl, &chip->work_space.session_tbl, 524 sizeof(space->session_tbl)); 525 memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE); 526 memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE); 527 528 return 0; 529 } 530