1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2017, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <bitstring.h> 8 #include <crypto/crypto.h> 9 #include <kernel/mutex.h> 10 #include <kernel/thread.h> 11 #include <mm/mobj.h> 12 #include <optee_rpc_cmd.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <tee_api_defines_extensions.h> 16 #include <tee/tadb.h> 17 #include <tee/tee_fs.h> 18 #include <tee/tee_fs_rpc.h> 19 #include <tee/tee_pobj.h> 20 #include <tee/tee_svc_storage.h> 21 #include <utee_defines.h> 22 23 #define TADB_MAX_BUFFER_SIZE (64U * 1024) 24 25 #define TADB_AUTH_ENC_ALG TEE_ALG_AES_GCM 26 #define TADB_IV_SIZE TEE_AES_BLOCK_SIZE 27 #define TADB_TAG_SIZE TEE_AES_BLOCK_SIZE 28 #define TADB_KEY_SIZE TEE_AES_MAX_KEY_SIZE 29 30 struct tee_tadb_dir { 31 const struct tee_file_operations *ops; 32 struct tee_file_handle *fh; 33 int nbits; 34 bitstr_t *files; 35 }; 36 37 struct tadb_entry { 38 struct tee_tadb_property prop; 39 uint32_t file_number; 40 uint8_t iv[TADB_IV_SIZE]; 41 uint8_t tag[TADB_TAG_SIZE]; 42 uint8_t key[TADB_KEY_SIZE]; 43 }; 44 45 struct tadb_header { 46 uint32_t opaque_len; 47 uint8_t opaque[]; 48 }; 49 50 struct tee_tadb_ta_write { 51 struct tee_tadb_dir *db; 52 int fd; 53 struct tadb_entry entry; 54 size_t pos; 55 void *ctx; 56 }; 57 58 struct tee_tadb_ta_read { 59 struct tee_tadb_dir *db; 60 int fd; 61 struct tadb_entry entry; 62 size_t pos; 63 void *ctx; 64 struct mobj *ta_mobj; 65 uint8_t *ta_buf; 66 }; 67 68 static const char tadb_obj_id[] = "ta.db"; 69 static struct tee_tadb_dir *tadb_db; 70 static unsigned int tadb_db_refc; 71 static struct mutex tadb_mutex = MUTEX_INITIALIZER; 72 73 static void file_num_to_str(char *buf, size_t blen, uint32_t file_number) 74 { 75 snprintf(buf, blen, "%" PRIu32 ".ta", file_number); 76 } 77 78 static bool is_null_uuid(const TEE_UUID *uuid) 79 { 80 const TEE_UUID null_uuid = { 0 }; 81 82 return !memcmp(uuid, &null_uuid, sizeof(*uuid)); 83 } 84 85 static TEE_Result ta_operation_open(unsigned int cmd, uint32_t file_number, 86 int *fd) 87 { 88 struct mobj *mobj; 89 TEE_Result res; 90 void *va; 91 92 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &mobj); 93 if (!va) 94 return TEE_ERROR_OUT_OF_MEMORY; 95 96 file_num_to_str(va, TEE_FS_NAME_MAX, file_number); 97 98 struct thread_param params[] = { 99 [0] = THREAD_PARAM_VALUE(IN, cmd, 0, 0), 100 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX), 101 [2] = THREAD_PARAM_VALUE(OUT, 0, 0, 0), 102 }; 103 104 res = thread_rpc_cmd(OPTEE_RPC_CMD_FS, ARRAY_SIZE(params), params); 105 if (!res) 106 *fd = params[2].u.value.a; 107 108 return res; 109 } 110 111 static TEE_Result ta_operation_remove(uint32_t file_number) 112 { 113 struct mobj *mobj; 114 void *va; 115 116 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &mobj); 117 if (!va) 118 return TEE_ERROR_OUT_OF_MEMORY; 119 120 file_num_to_str(va, TEE_FS_NAME_MAX, file_number); 121 122 struct thread_param params[] = { 123 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_REMOVE, 0, 0), 124 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX), 125 }; 126 127 return thread_rpc_cmd(OPTEE_RPC_CMD_FS, ARRAY_SIZE(params), params); 128 } 129 130 static TEE_Result maybe_grow_files(struct tee_tadb_dir *db, int idx) 131 { 132 void *p; 133 134 if (idx < db->nbits) 135 return TEE_SUCCESS; 136 137 p = realloc(db->files, bitstr_size(idx + 1)); 138 if (!p) 139 return TEE_ERROR_OUT_OF_MEMORY; 140 db->files = p; 141 142 bit_nclear(db->files, db->nbits, idx); 143 db->nbits = idx + 1; 144 145 return TEE_SUCCESS; 146 } 147 148 static TEE_Result set_file(struct tee_tadb_dir *db, int idx) 149 { 150 TEE_Result res = maybe_grow_files(db, idx); 151 152 if (!res) 153 bit_set(db->files, idx); 154 155 return res; 156 } 157 158 static void clear_file(struct tee_tadb_dir *db, int idx) 159 { 160 if (idx < db->nbits) 161 bit_clear(db->files, idx); 162 } 163 164 static bool test_file(struct tee_tadb_dir *db, int idx) 165 { 166 if (idx < db->nbits) 167 return bit_test(db->files, idx); 168 169 return false; 170 } 171 172 static TEE_Result read_ent(struct tee_tadb_dir *db, size_t idx, 173 struct tadb_entry *entry) 174 { 175 size_t l = sizeof(*entry); 176 TEE_Result res = db->ops->read(db->fh, idx * l, entry, &l); 177 178 if (!res && l != sizeof(*entry)) 179 return TEE_ERROR_ITEM_NOT_FOUND; 180 181 return res; 182 } 183 184 static TEE_Result write_ent(struct tee_tadb_dir *db, size_t idx, 185 const struct tadb_entry *entry) 186 { 187 const size_t l = sizeof(*entry); 188 189 return db->ops->write(db->fh, idx * l, entry, l); 190 } 191 192 static TEE_Result tadb_open(struct tee_tadb_dir **db_ret) 193 { 194 TEE_Result res; 195 struct tee_tadb_dir *db = calloc(1, sizeof(*db)); 196 struct tee_pobj po = { 197 .obj_id = (void *)tadb_obj_id, 198 .obj_id_len = sizeof(tadb_obj_id) 199 }; 200 201 if (!db) 202 return TEE_ERROR_OUT_OF_MEMORY; 203 204 db->ops = tee_svc_storage_file_ops(TEE_STORAGE_PRIVATE); 205 206 res = db->ops->open(&po, NULL, &db->fh); 207 if (res == TEE_ERROR_ITEM_NOT_FOUND) 208 res = db->ops->create(&po, false, NULL, 0, NULL, 0, NULL, 0, 209 &db->fh); 210 211 if (res) 212 free(db); 213 else 214 *db_ret = db; 215 216 return res; 217 } 218 219 static TEE_Result tee_tadb_open(struct tee_tadb_dir **db) 220 { 221 TEE_Result res = TEE_SUCCESS; 222 223 mutex_lock(&tadb_mutex); 224 if (!tadb_db_refc) { 225 assert(!tadb_db); 226 res = tadb_open(&tadb_db); 227 if (res) 228 goto err; 229 } 230 tadb_db_refc++; 231 *db = tadb_db; 232 err: 233 mutex_unlock(&tadb_mutex); 234 return res; 235 } 236 237 static void tadb_put(struct tee_tadb_dir *db) 238 { 239 assert(db == tadb_db); 240 mutex_lock(&tadb_mutex); 241 assert(tadb_db_refc); 242 tadb_db_refc--; 243 if (!tadb_db_refc) { 244 db->ops->close(&db->fh); 245 free(db->files); 246 free(db); 247 tadb_db = NULL; 248 } 249 mutex_unlock(&tadb_mutex); 250 } 251 252 static void tee_tadb_close(struct tee_tadb_dir *db) 253 { 254 tadb_put(db); 255 } 256 257 static TEE_Result tadb_authenc_init(TEE_OperationMode mode, 258 const struct tadb_entry *entry, 259 void **ctx_ret) 260 { 261 TEE_Result res; 262 void *ctx; 263 const size_t enc_size = entry->prop.custom_size + entry->prop.bin_size; 264 265 res = crypto_authenc_alloc_ctx(&ctx, TADB_AUTH_ENC_ALG); 266 if (res) 267 return res; 268 269 res = crypto_authenc_init(ctx, TADB_AUTH_ENC_ALG, mode, 270 entry->key, sizeof(entry->key), 271 entry->iv, sizeof(entry->iv), 272 sizeof(entry->tag), 0, enc_size); 273 if (res) 274 crypto_authenc_free_ctx(ctx, TADB_AUTH_ENC_ALG); 275 else 276 *ctx_ret = ctx; 277 278 return res; 279 } 280 281 static TEE_Result tadb_update_payload(void *ctx, TEE_OperationMode mode, 282 const void *src, size_t len, void *dst) 283 { 284 TEE_Result res; 285 size_t sz = len; 286 287 res = crypto_authenc_update_payload(ctx, TADB_AUTH_ENC_ALG, mode, 288 (const uint8_t *)src, len, dst, 289 &sz); 290 assert(res || sz == len); 291 return res; 292 } 293 294 static TEE_Result populate_files(struct tee_tadb_dir *db) 295 { 296 TEE_Result res; 297 size_t idx; 298 299 /* 300 * If db->files isn't NULL the bitfield is already populated and 301 * there's nothing left to do here for now. 302 */ 303 if (db->files) 304 return TEE_SUCCESS; 305 306 /* 307 * Iterate over the TA database and set the bits in the bit field 308 * for used file numbers. Note that set_file() will allocate and 309 * grow the bitfield as needed. 310 * 311 * At the same time clean out duplicate file numbers, the first 312 * entry with the file number has precedence. Duplicate entries is 313 * not supposed to be able to happen, but if it still does better 314 * to clean it out here instead of letting the error spread with 315 * unexpected side effects. 316 */ 317 for (idx = 0;; idx++) { 318 struct tadb_entry entry; 319 320 res = read_ent(db, idx, &entry); 321 if (res) { 322 if (res == TEE_ERROR_ITEM_NOT_FOUND) 323 return TEE_SUCCESS; 324 goto err; 325 } 326 327 if (is_null_uuid(&entry.prop.uuid)) 328 continue; 329 330 if (test_file(db, entry.file_number)) { 331 IMSG("Clearing duplicate file number %" PRIu32, 332 entry.file_number); 333 memset(&entry, 0, sizeof(entry)); 334 res = write_ent(db, idx, &entry); 335 if (res) 336 goto err; 337 continue; 338 } 339 340 res = set_file(db, entry.file_number); 341 if (res) 342 goto err; 343 } 344 345 err: 346 free(db->files); 347 db->files = NULL; 348 db->nbits = 0; 349 350 return res; 351 } 352 353 TEE_Result tee_tadb_ta_create(const struct tee_tadb_property *property, 354 struct tee_tadb_ta_write **ta_ret) 355 { 356 TEE_Result res; 357 struct tee_tadb_ta_write *ta; 358 int i = 0; 359 360 if (is_null_uuid(&property->uuid)) 361 return TEE_ERROR_GENERIC; 362 363 ta = calloc(1, sizeof(*ta)); 364 if (!ta) 365 return TEE_ERROR_OUT_OF_MEMORY; 366 367 res = tee_tadb_open(&ta->db); 368 if (res) 369 goto err_free; 370 371 mutex_lock(&tadb_mutex); 372 373 /* 374 * Since we're going to search for next free file number below we 375 * need to populate the bitfield holding used file numbers. 376 */ 377 res = populate_files(ta->db); 378 if (res) 379 goto err_mutex; 380 381 if (ta->db->files) { 382 bit_ffc(ta->db->files, ta->db->nbits, &i); 383 if (i == -1) 384 i = ta->db->nbits; 385 } 386 387 res = set_file(ta->db, i); 388 if (res) 389 goto err_mutex; 390 391 mutex_unlock(&tadb_mutex); 392 393 ta->entry.file_number = i; 394 ta->entry.prop = *property; 395 396 res = crypto_rng_read(ta->entry.iv, sizeof(ta->entry.iv)); 397 if (res) 398 goto err_put; 399 400 res = crypto_rng_read(ta->entry.key, sizeof(ta->entry.key)); 401 if (res) 402 goto err_put; 403 404 res = ta_operation_open(OPTEE_RPC_FS_CREATE, ta->entry.file_number, 405 &ta->fd); 406 if (res) 407 goto err_put; 408 409 res = tadb_authenc_init(TEE_MODE_ENCRYPT, &ta->entry, &ta->ctx); 410 if (res) 411 goto err_put; 412 413 *ta_ret = ta; 414 415 return TEE_SUCCESS; 416 417 err_mutex: 418 mutex_unlock(&tadb_mutex); 419 err_put: 420 tadb_put(ta->db); 421 err_free: 422 free(ta); 423 424 return res; 425 } 426 427 TEE_Result tee_tadb_ta_write(struct tee_tadb_ta_write *ta, const void *buf, 428 size_t len) 429 { 430 TEE_Result res; 431 const uint8_t *rb = buf; 432 size_t rl = len; 433 struct tee_fs_rpc_operation op; 434 435 while (rl) { 436 size_t wl = MIN(rl, TADB_MAX_BUFFER_SIZE); 437 void *wb; 438 439 res = tee_fs_rpc_write_init(&op, OPTEE_RPC_CMD_FS, ta->fd, 440 ta->pos, wl, &wb); 441 if (res) 442 return res; 443 444 res = tadb_update_payload(ta->ctx, TEE_MODE_ENCRYPT, 445 rb, wl, wb); 446 if (res) 447 return res; 448 449 res = tee_fs_rpc_write_final(&op); 450 if (res) 451 return res; 452 453 rl -= wl; 454 rb += wl; 455 ta->pos += wl; 456 } 457 458 return TEE_SUCCESS; 459 } 460 461 void tee_tadb_ta_close_and_delete(struct tee_tadb_ta_write *ta) 462 { 463 crypto_authenc_final(ta->ctx, TADB_AUTH_ENC_ALG); 464 crypto_authenc_free_ctx(ta->ctx, TADB_AUTH_ENC_ALG); 465 tee_fs_rpc_close(OPTEE_RPC_CMD_FS, ta->fd); 466 ta_operation_remove(ta->entry.file_number); 467 468 mutex_lock(&tadb_mutex); 469 clear_file(ta->db, ta->entry.file_number); 470 mutex_unlock(&tadb_mutex); 471 472 tadb_put(ta->db); 473 free(ta); 474 } 475 476 static TEE_Result find_ent(struct tee_tadb_dir *db, const TEE_UUID *uuid, 477 size_t *idx_ret, struct tadb_entry *entry_ret) 478 { 479 TEE_Result res; 480 size_t idx; 481 482 /* 483 * Search for the provided uuid, if it's found return the index it 484 * has together with TEE_SUCCESS. 485 * 486 * If the uuid can't be found return the number indexes together 487 * with TEE_ERROR_ITEM_NOT_FOUND. 488 */ 489 for (idx = 0;; idx++) { 490 struct tadb_entry entry; 491 492 res = read_ent(db, idx, &entry); 493 if (res) { 494 if (res == TEE_ERROR_ITEM_NOT_FOUND) 495 break; 496 return res; 497 } 498 499 if (!memcmp(&entry.prop.uuid, uuid, sizeof(*uuid))) { 500 if (entry_ret) 501 *entry_ret = entry; 502 break; 503 } 504 } 505 506 *idx_ret = idx; 507 return res; 508 } 509 510 static TEE_Result find_free_ent_idx(struct tee_tadb_dir *db, size_t *idx) 511 { 512 const TEE_UUID null_uuid = { 0 }; 513 TEE_Result res = find_ent(db, &null_uuid, idx, NULL); 514 515 /* 516 * Note that *idx is set to the number of entries on 517 * TEE_ERROR_ITEM_NOT_FOUND. 518 */ 519 if (res == TEE_ERROR_ITEM_NOT_FOUND) 520 return TEE_SUCCESS; 521 return res; 522 } 523 524 TEE_Result tee_tadb_ta_close_and_commit(struct tee_tadb_ta_write *ta) 525 { 526 TEE_Result res; 527 size_t dsz = 0; 528 size_t sz = sizeof(ta->entry.tag); 529 size_t idx; 530 struct tadb_entry old_ent; 531 bool have_old_ent = false; 532 533 res = crypto_authenc_enc_final(ta->ctx, TADB_AUTH_ENC_ALG, 534 NULL, 0, NULL, &dsz, 535 ta->entry.tag, &sz); 536 if (res) 537 goto err; 538 539 tee_fs_rpc_close(OPTEE_RPC_CMD_FS, ta->fd); 540 541 mutex_lock(&tadb_mutex); 542 /* 543 * First try to find an existing TA to replace. If there's one 544 * we'll use the entry, but we should also remove the old encrypted 545 * file. 546 * 547 * If there isn't an existing TA to replace, grab a new entry. 548 */ 549 res = find_ent(ta->db, &ta->entry.prop.uuid, &idx, &old_ent); 550 if (!res) { 551 have_old_ent = true; 552 } else { 553 res = find_free_ent_idx(ta->db, &idx); 554 if (res) 555 goto err_mutex; 556 } 557 res = write_ent(ta->db, idx, &ta->entry); 558 if (res) 559 goto err_mutex; 560 if (have_old_ent) 561 clear_file(ta->db, old_ent.file_number); 562 mutex_unlock(&tadb_mutex); 563 564 crypto_authenc_final(ta->ctx, TADB_AUTH_ENC_ALG); 565 crypto_authenc_free_ctx(ta->ctx, TADB_AUTH_ENC_ALG); 566 tadb_put(ta->db); 567 free(ta); 568 if (have_old_ent) 569 ta_operation_remove(old_ent.file_number); 570 return TEE_SUCCESS; 571 572 err_mutex: 573 mutex_unlock(&tadb_mutex); 574 err: 575 tee_tadb_ta_close_and_delete(ta); 576 return res; 577 } 578 579 TEE_Result tee_tadb_ta_delete(const TEE_UUID *uuid) 580 { 581 const struct tadb_entry null_entry = { { { 0 } } }; 582 struct tee_tadb_dir *db; 583 struct tadb_entry entry; 584 size_t idx; 585 TEE_Result res; 586 587 if (is_null_uuid(uuid)) 588 return TEE_ERROR_GENERIC; 589 590 res = tee_tadb_open(&db); 591 if (res) 592 return res; 593 594 mutex_lock(&tadb_mutex); 595 res = find_ent(db, uuid, &idx, &entry); 596 if (res) { 597 mutex_unlock(&tadb_mutex); 598 tee_tadb_close(db); 599 return res; 600 } 601 602 clear_file(db, entry.file_number); 603 res = write_ent(db, idx, &null_entry); 604 mutex_unlock(&tadb_mutex); 605 606 tee_tadb_close(db); 607 if (res) 608 return res; 609 610 ta_operation_remove(entry.file_number); 611 return TEE_SUCCESS; 612 } 613 614 TEE_Result tee_tadb_ta_open(const TEE_UUID *uuid, 615 struct tee_tadb_ta_read **ta_ret) 616 { 617 TEE_Result res; 618 size_t idx; 619 struct tee_tadb_ta_read *ta; 620 static struct tadb_entry last_entry; 621 622 if (is_null_uuid(uuid)) 623 return TEE_ERROR_GENERIC; 624 625 ta = calloc(1, sizeof(*ta)); 626 if (!ta) 627 return TEE_ERROR_OUT_OF_MEMORY; 628 629 if (!memcmp(uuid, &last_entry.prop.uuid, sizeof(*uuid))) { 630 ta->entry = last_entry; 631 } else { 632 res = tee_tadb_open(&ta->db); 633 if (res) 634 goto err_free; /* Mustn't all tadb_put() */ 635 636 mutex_read_lock(&tadb_mutex); 637 res = find_ent(ta->db, uuid, &idx, &ta->entry); 638 mutex_read_unlock(&tadb_mutex); 639 if (res) 640 goto err; 641 } 642 643 res = ta_operation_open(OPTEE_RPC_FS_OPEN, ta->entry.file_number, 644 &ta->fd); 645 if (res) 646 goto err; 647 648 res = tadb_authenc_init(TEE_MODE_DECRYPT, &ta->entry, &ta->ctx); 649 if (res) 650 goto err; 651 652 *ta_ret = ta; 653 654 return TEE_SUCCESS; 655 err: 656 tadb_put(ta->db); 657 err_free: 658 free(ta); 659 return res; 660 } 661 662 const struct tee_tadb_property * 663 tee_tadb_ta_get_property(struct tee_tadb_ta_read *ta) 664 { 665 return &ta->entry.prop; 666 } 667 668 TEE_Result tee_tadb_get_tag(struct tee_tadb_ta_read *ta, uint8_t *tag, 669 unsigned int *tag_len) 670 { 671 if (!tag || *tag_len < sizeof(ta->entry.tag)) { 672 *tag_len = sizeof(ta->entry.tag); 673 return TEE_ERROR_SHORT_BUFFER; 674 } 675 *tag_len = sizeof(ta->entry.tag); 676 677 memcpy(tag, ta->entry.tag, sizeof(ta->entry.tag)); 678 679 return TEE_SUCCESS; 680 } 681 682 static TEE_Result ta_load(struct tee_tadb_ta_read *ta) 683 { 684 TEE_Result res; 685 const size_t sz = ta->entry.prop.custom_size + ta->entry.prop.bin_size; 686 687 if (ta->ta_mobj) 688 return TEE_SUCCESS; 689 690 ta->ta_mobj = thread_rpc_alloc_payload(sz); 691 if (!ta->ta_mobj) 692 return TEE_ERROR_OUT_OF_MEMORY; 693 694 ta->ta_buf = mobj_get_va(ta->ta_mobj, 0); 695 assert(ta->ta_buf); 696 697 struct thread_param params[] = { 698 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_READ, ta->fd, 0), 699 [1] = THREAD_PARAM_MEMREF(OUT, ta->ta_mobj, 0, sz), 700 }; 701 702 res = thread_rpc_cmd(OPTEE_RPC_CMD_FS, ARRAY_SIZE(params), params); 703 if (res) { 704 thread_rpc_free_payload(ta->ta_mobj); 705 ta->ta_mobj = NULL; 706 } 707 return res; 708 } 709 710 TEE_Result tee_tadb_ta_read(struct tee_tadb_ta_read *ta, void *buf, size_t *len) 711 { 712 TEE_Result res; 713 const size_t sz = ta->entry.prop.custom_size + ta->entry.prop.bin_size; 714 size_t l = MIN(*len, sz - ta->pos); 715 716 res = ta_load(ta); 717 if (res) 718 return res; 719 720 if (buf) { 721 res = tadb_update_payload(ta->ctx, TEE_MODE_DECRYPT, 722 ta->ta_buf + ta->pos, l, buf); 723 if (res) 724 return res; 725 } else { 726 size_t num_bytes = 0; 727 size_t b_size = MIN(256U, l); 728 uint8_t *b = malloc(b_size); 729 730 if (!b) 731 return TEE_ERROR_OUT_OF_MEMORY; 732 733 while (num_bytes < l) { 734 size_t n = MIN(b_size, l - num_bytes); 735 736 res = tadb_update_payload(ta->ctx, TEE_MODE_DECRYPT, 737 ta->ta_buf + ta->pos + 738 num_bytes, n, b); 739 if (res) 740 break; 741 num_bytes += n; 742 } 743 744 free(b); 745 if (res) 746 return res; 747 } 748 749 ta->pos += l; 750 if (ta->pos == sz) { 751 size_t dl = 0; 752 753 res = crypto_authenc_dec_final(ta->ctx, TADB_AUTH_ENC_ALG, 754 NULL, 0, NULL, &dl, 755 ta->entry.tag, TADB_TAG_SIZE); 756 if (res) 757 return res; 758 } 759 *len = l; 760 return TEE_SUCCESS; 761 } 762 763 void tee_tadb_ta_close(struct tee_tadb_ta_read *ta) 764 { 765 crypto_authenc_final(ta->ctx, TADB_AUTH_ENC_ALG); 766 crypto_authenc_free_ctx(ta->ctx, TADB_AUTH_ENC_ALG); 767 if (ta->ta_mobj) 768 thread_rpc_free_payload(ta->ta_mobj); 769 tee_fs_rpc_close(OPTEE_RPC_CMD_FS, ta->fd); 770 tadb_put(ta->db); 771 free(ta); 772 } 773