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