1 /* 2 * Copyright (c) 2014, STMicroelectronics International N.V. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <kernel/mutex.h> 29 #include <kernel/tee_ta_manager.h> 30 #include <kernel/tee_misc.h> 31 #include <mm/tee_mmu.h> 32 #include <tee/tee_fs.h> 33 #include <tee/tee_fs_defs.h> 34 #include <tee/tee_obj.h> 35 #include <tee/tee_svc.h> 36 #include <tee/tee_pobj.h> 37 #include <tee/tee_svc_storage.h> 38 #include <tee/tee_svc_cryp.h> 39 #include <tee_api_defines.h> 40 #include <tee_api_defines_extensions.h> 41 #include <trace.h> 42 43 /* 44 * Returns the appropriate tee_file_operations for the specified storage ID. 45 * The value TEE_STORAGE_PRIVATE will select the REE FS if available, otherwise 46 * RPMB. 47 */ 48 static const struct tee_file_operations *file_ops(uint32_t storage_id) 49 { 50 51 switch (storage_id) { 52 case TEE_STORAGE_PRIVATE: 53 #if defined(CFG_REE_FS) 54 return &ree_fs_ops; 55 #elif defined(CFG_RPMB_FS) 56 return &rpmb_fs_ops; 57 #elif defined(CFG_SQL_FS) 58 return &sql_fs_ops; 59 #else 60 #error At least one filesystem must be enabled. 61 #endif 62 #ifdef CFG_REE_FS 63 case TEE_STORAGE_PRIVATE_REE: 64 return &ree_fs_ops; 65 #endif 66 #ifdef CFG_RPMB_FS 67 case TEE_STORAGE_PRIVATE_RPMB: 68 return &rpmb_fs_ops; 69 #endif 70 #ifdef CFG_SQL_FS 71 case TEE_STORAGE_PRIVATE_SQL: 72 return &sql_fs_ops; 73 #endif 74 default: 75 return NULL; 76 } 77 } 78 79 /* SSF (Secure Storage File version 00 */ 80 #define TEE_SVC_STORAGE_MAGIC 0x53534600; 81 82 /* Header of GP formated secure storage files */ 83 struct tee_svc_storage_head { 84 uint32_t magic; 85 uint32_t head_size; 86 uint32_t meta_size; 87 uint32_t ds_size; 88 uint32_t keySize; 89 uint32_t maxKeySize; 90 uint32_t objectUsage; 91 uint32_t objectType; 92 uint32_t have_attrs; 93 }; 94 95 struct tee_storage_enum { 96 TAILQ_ENTRY(tee_storage_enum) link; 97 struct tee_fs_dir *dir; 98 const struct tee_file_operations *fops; 99 }; 100 101 /* 102 * Protect TA storage directory: avoid race conditions between (create 103 * directory + create file) and (remove directory) 104 */ 105 static struct mutex ta_dir_mutex = MUTEX_INITIALIZER; 106 107 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc, 108 uint32_t enum_id, 109 struct tee_storage_enum **e_out) 110 { 111 struct tee_storage_enum *e; 112 113 TAILQ_FOREACH(e, &utc->storage_enums, link) { 114 if (enum_id == (vaddr_t)e) { 115 *e_out = e; 116 return TEE_SUCCESS; 117 } 118 } 119 return TEE_ERROR_BAD_PARAMETERS; 120 } 121 122 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc, 123 struct tee_storage_enum *e) 124 { 125 int ret; 126 127 if (e == NULL || utc == NULL) 128 return TEE_ERROR_BAD_PARAMETERS; 129 130 TAILQ_REMOVE(&utc->storage_enums, e, link); 131 132 if (!e->fops) 133 return TEE_ERROR_ITEM_NOT_FOUND; 134 135 ret = e->fops->closedir(e->dir); 136 e->dir = NULL; 137 e->fops = NULL; 138 139 free(e); 140 141 if (ret != 0) 142 return TEE_ERROR_ITEM_NOT_FOUND; 143 144 return TEE_SUCCESS; 145 } 146 147 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */ 148 char *tee_svc_storage_create_filename(struct tee_ta_session *sess, 149 void *object_id, 150 uint32_t object_id_len, 151 bool transient) 152 { 153 uint8_t *file; 154 uint32_t pos = 0; 155 uint32_t hslen = 1 /* Leading slash */ 156 + TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len) 157 + 1; /* Intermediate slash */ 158 159 /* +1 for the '.' (temporary persistent object) */ 160 if (transient) 161 hslen++; 162 163 file = malloc(hslen); 164 if (!file) 165 return NULL; 166 167 file[pos++] = '/'; 168 pos += tee_b2hs((uint8_t *)&sess->ctx->uuid, &file[pos], 169 sizeof(TEE_UUID), hslen); 170 file[pos++] = '/'; 171 172 if (transient) 173 file[pos++] = '.'; 174 175 tee_b2hs(object_id, file + pos, object_id_len, hslen - pos); 176 177 return (char *)file; 178 } 179 180 /* "/TA_uuid" */ 181 char *tee_svc_storage_create_dirname(struct tee_ta_session *sess) 182 { 183 uint8_t *dir; 184 uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1; 185 186 dir = malloc(hslen); 187 if (!dir) 188 return NULL; 189 190 dir[0] = '/'; 191 tee_b2hs((uint8_t *)&sess->ctx->uuid, dir + 1, sizeof(TEE_UUID), 192 hslen); 193 194 return (char *)dir; 195 } 196 197 static TEE_Result tee_svc_storage_remove_corrupt_obj( 198 struct tee_ta_session *sess, 199 struct tee_obj *o) 200 { 201 TEE_Result res; 202 char *file = NULL; 203 char *dir = NULL; 204 const struct tee_file_operations *fops = o->pobj->fops; 205 206 file = tee_svc_storage_create_filename(sess, 207 o->pobj->obj_id, 208 o->pobj->obj_id_len, 209 false); 210 if (file == NULL) { 211 res = TEE_ERROR_OUT_OF_MEMORY; 212 goto exit; 213 } 214 215 tee_obj_close(to_user_ta_ctx(sess->ctx), o); 216 fops->unlink(file); 217 free(file); 218 dir = tee_svc_storage_create_dirname(sess); 219 if (dir != NULL) { 220 mutex_lock(&ta_dir_mutex); 221 fops->rmdir(dir); 222 mutex_unlock(&ta_dir_mutex); 223 free(dir); 224 } 225 226 res = TEE_SUCCESS; 227 228 exit: 229 return res; 230 } 231 232 static uint32_t tee_svc_storage_conv_oflags(uint32_t flags) 233 { 234 const uint32_t write_access = TEE_DATA_FLAG_ACCESS_WRITE | 235 TEE_DATA_FLAG_ACCESS_WRITE_META | 236 TEE_DATA_FLAG_SHARE_WRITE; 237 const uint32_t read_access = TEE_DATA_FLAG_ACCESS_READ | 238 TEE_DATA_FLAG_SHARE_READ; 239 240 if (flags & write_access) 241 return TEE_FS_O_RDWR; 242 if (flags & read_access) 243 return TEE_FS_O_RDONLY; 244 return 0; 245 } 246 247 static int tee_svc_storage_conv_whence(TEE_Whence whence) 248 { 249 switch (whence) { 250 case TEE_DATA_SEEK_SET: 251 return TEE_FS_SEEK_SET; 252 case TEE_DATA_SEEK_CUR: 253 return TEE_FS_SEEK_CUR; 254 case TEE_DATA_SEEK_END: 255 return TEE_FS_SEEK_END; 256 default: 257 return -1; 258 } 259 } 260 261 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess, 262 char *file, 263 const struct tee_file_operations *fops, 264 int *fd) 265 { 266 TEE_Result res = TEE_SUCCESS; 267 TEE_Result errno; 268 char *dir = NULL; 269 int tmp; 270 int err; 271 uint32_t cflags = TEE_FS_O_WRONLY | 272 TEE_FS_O_CREATE | TEE_FS_O_TRUNC; 273 274 dir = tee_svc_storage_create_dirname(sess); 275 if (dir == NULL) { 276 res = TEE_ERROR_OUT_OF_MEMORY; 277 goto exit; 278 } 279 280 mutex_lock(&ta_dir_mutex); 281 282 /* try and make directory */ 283 err = fops->access(dir, TEE_FS_F_OK); 284 if (err) { 285 /* directory does not exists */ 286 tmp = fops->mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR | 287 TEE_FS_S_IXUSR); 288 289 if (tmp < 0) { 290 /* error codes needs better granularity */ 291 res = TEE_ERROR_GENERIC; 292 goto unlock; 293 } 294 } 295 296 /* try and open again */ 297 *fd = fops->open(&errno, file, cflags); 298 if (*fd < 0) 299 res = errno; 300 301 unlock: 302 mutex_unlock(&ta_dir_mutex); 303 exit: 304 free(dir); 305 306 return res; 307 } 308 309 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess, 310 struct tee_obj *o) 311 { 312 TEE_Result res = TEE_SUCCESS; 313 TEE_Result errno; 314 int err; 315 struct tee_svc_storage_head head; 316 char *file = NULL; 317 const struct tee_file_operations *fops; 318 void *attr = NULL; 319 int fs_flags; 320 321 if (o == NULL || o->pobj == NULL) 322 return TEE_ERROR_BAD_PARAMETERS; 323 324 fs_flags = tee_svc_storage_conv_oflags(o->flags); 325 fops = o->pobj->fops; 326 327 file = tee_svc_storage_create_filename(sess, 328 o->pobj->obj_id, 329 o->pobj->obj_id_len, 330 false); 331 if (file == NULL) { 332 res = TEE_ERROR_OUT_OF_MEMORY; 333 goto exit; 334 } 335 336 if (fops->access(file, TEE_FS_F_OK)) { 337 /* file not found */ 338 res = TEE_ERROR_ITEM_NOT_FOUND; 339 goto exit; 340 } 341 342 assert(o->fd == -1); 343 o->fd = fops->open(&errno, file, fs_flags); 344 if (o->fd < 0) { 345 res = errno; 346 goto exit; 347 } 348 349 /* read head */ 350 err = fops->read(&errno, o->fd, &head, 351 sizeof(struct tee_svc_storage_head)); 352 if (err < 0) { 353 res = errno; 354 if (res == TEE_ERROR_CORRUPT_OBJECT) 355 EMSG("Head corrupt\n"); 356 goto exit; 357 } 358 359 if (err != sizeof(struct tee_svc_storage_head)) { 360 res = TEE_ERROR_BAD_FORMAT; 361 goto exit; 362 } 363 364 res = tee_obj_set_type(o, head.objectType, head.maxKeySize); 365 if (res != TEE_SUCCESS) 366 goto exit; 367 368 if (head.meta_size) { 369 attr = malloc(head.meta_size); 370 if (!attr) { 371 res = TEE_ERROR_OUT_OF_MEMORY; 372 goto exit; 373 } 374 375 /* read meta */ 376 err = fops->read(&errno, o->fd, attr, head.meta_size); 377 if (err != (int)head.meta_size) { 378 res = TEE_ERROR_CORRUPT_OBJECT; 379 goto exit; 380 } 381 } 382 383 res = tee_obj_attr_from_binary(o, attr, head.meta_size); 384 if (res != TEE_SUCCESS) 385 goto exit; 386 387 o->info.dataSize = head.ds_size; 388 o->info.keySize = head.keySize; 389 o->info.objectUsage = head.objectUsage; 390 o->info.objectType = head.objectType; 391 o->have_attrs = head.have_attrs; 392 393 exit: 394 free(attr); 395 free(file); 396 397 return res; 398 } 399 400 401 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess, 402 struct tee_obj *o, 403 struct tee_obj *attr_o, void *data, 404 uint32_t len) 405 { 406 TEE_Result res = TEE_SUCCESS; 407 TEE_Result errno; 408 int fd = -1; 409 int err = -1; 410 struct tee_svc_storage_head head; 411 char *tmpfile = NULL; 412 const struct tee_file_operations *fops; 413 void *attr = NULL; 414 size_t attr_size = 0; 415 416 if (o == NULL || o->pobj == NULL) 417 return TEE_ERROR_BAD_PARAMETERS; 418 419 fops = o->pobj->fops; 420 421 /* create temporary persistent object filename */ 422 tmpfile = tee_svc_storage_create_filename(sess, 423 o->pobj->obj_id, 424 o->pobj->obj_id_len, 425 true); 426 427 if (tmpfile == NULL) { 428 res = TEE_ERROR_OUT_OF_MEMORY; 429 goto exit; 430 } 431 432 res = tee_svc_storage_create_file(sess, tmpfile, fops, &fd); 433 if (res != TEE_SUCCESS) 434 goto exit; 435 436 if (attr_o) { 437 res = tee_obj_set_type(o, attr_o->info.objectType, 438 attr_o->info.maxKeySize); 439 if (res != TEE_SUCCESS) 440 goto exit; 441 res = tee_obj_attr_copy_from(o, attr_o); 442 if (res != TEE_SUCCESS) 443 goto exit; 444 o->have_attrs = attr_o->have_attrs; 445 o->info.objectUsage = attr_o->info.objectUsage; 446 o->info.keySize = attr_o->info.keySize; 447 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 448 if (res != TEE_SUCCESS) 449 goto exit; 450 if (attr_size) { 451 attr = malloc(attr_size); 452 if (!attr) { 453 res = TEE_ERROR_OUT_OF_MEMORY; 454 goto exit; 455 } 456 res = tee_obj_attr_to_binary(o, attr, &attr_size); 457 if (res != TEE_SUCCESS) 458 goto exit; 459 } 460 } else { 461 res = tee_obj_set_type(o, TEE_TYPE_DATA, 0); 462 if (res != TEE_SUCCESS) 463 goto exit; 464 } 465 466 /* write head */ 467 head.magic = TEE_SVC_STORAGE_MAGIC; 468 head.head_size = sizeof(struct tee_svc_storage_head); 469 head.meta_size = attr_size; 470 head.ds_size = len; 471 head.keySize = o->info.keySize; 472 head.maxKeySize = o->info.maxKeySize; 473 head.objectUsage = o->info.objectUsage; 474 head.objectType = o->info.objectType; 475 head.have_attrs = o->have_attrs; 476 477 /* write head */ 478 err = fops->write(&errno, fd, &head, 479 sizeof(struct tee_svc_storage_head)); 480 if (err < 0) 481 res = errno; 482 if (err != sizeof(struct tee_svc_storage_head)) 483 goto exit; 484 485 /* write meta */ 486 err = fops->write(&errno, fd, attr, attr_size); 487 if (err < 0) 488 res = errno; 489 if (err != (int)attr_size) 490 goto exit; 491 492 /* write init data */ 493 o->info.dataSize = len; 494 495 /* write data to fs if needed */ 496 if (data && len) { 497 err = fops->write(&errno, fd, data, len); 498 if (err < 0) 499 res = errno; 500 if (err != (int)len) 501 goto exit; 502 } 503 504 exit: 505 free(attr); 506 free(tmpfile); 507 tmpfile = NULL; 508 if (fd != -1) 509 fops->close(fd); 510 511 return res; 512 } 513 514 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id, 515 size_t object_id_len, unsigned long flags, 516 uint32_t *obj) 517 { 518 TEE_Result res; 519 TEE_Result errno; 520 struct tee_ta_session *sess; 521 struct tee_obj *o = NULL; 522 char *file = NULL; 523 tee_fs_off_t off; 524 tee_fs_off_t e_off; 525 struct tee_pobj *po = NULL; 526 struct user_ta_ctx *utc; 527 const struct tee_file_operations *fops = file_ops(storage_id); 528 size_t attr_size; 529 530 if (!fops) { 531 res = TEE_ERROR_ITEM_NOT_FOUND; 532 goto exit; 533 } 534 535 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) { 536 res = TEE_ERROR_BAD_PARAMETERS; 537 goto exit; 538 } 539 540 res = tee_ta_get_current_session(&sess); 541 if (res != TEE_SUCCESS) 542 goto err; 543 utc = to_user_ta_ctx(sess->ctx); 544 545 res = tee_mmu_check_access_rights(utc, 546 TEE_MEMORY_ACCESS_READ | 547 TEE_MEMORY_ACCESS_ANY_OWNER, 548 (tee_uaddr_t) object_id, 549 object_id_len); 550 if (res != TEE_SUCCESS) 551 goto err; 552 553 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 554 object_id_len, flags, fops, &po); 555 if (res != TEE_SUCCESS) 556 goto err; 557 558 o = tee_obj_alloc(); 559 if (o == NULL) { 560 tee_pobj_release(po); 561 res = TEE_ERROR_OUT_OF_MEMORY; 562 goto err; 563 } 564 565 o->info.handleFlags = 566 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 567 o->flags = flags; 568 o->pobj = po; 569 tee_obj_add(utc, o); 570 571 res = tee_svc_storage_read_head(sess, o); 572 if (res != TEE_SUCCESS) { 573 if (res == TEE_ERROR_CORRUPT_OBJECT) { 574 EMSG("Object corrupt"); 575 goto err; 576 } 577 goto oclose; 578 } 579 580 res = tee_svc_copy_kaddr_to_uref(obj, o); 581 if (res != TEE_SUCCESS) 582 goto oclose; 583 584 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 585 if (res != TEE_SUCCESS && res) 586 goto oclose; 587 588 e_off = sizeof(struct tee_svc_storage_head) + attr_size; 589 off = fops->lseek(&errno, o->fd, e_off, TEE_FS_SEEK_SET); 590 if (off != e_off) { 591 res = TEE_ERROR_NO_DATA; 592 goto err; 593 } else { 594 res = TEE_SUCCESS; 595 } 596 597 goto exit; 598 599 oclose: 600 tee_obj_close(utc, o); 601 o = NULL; 602 603 err: 604 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 605 res = TEE_ERROR_CORRUPT_OBJECT; 606 if (res == TEE_ERROR_CORRUPT_OBJECT && o) 607 tee_svc_storage_remove_corrupt_obj(sess, o); 608 609 exit: 610 free(file); 611 file = NULL; 612 return res; 613 } 614 615 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id, 616 size_t object_id_len, unsigned long flags, 617 unsigned long attr, void *data, size_t len, 618 uint32_t *obj) 619 { 620 TEE_Result res; 621 TEE_Result errno; 622 struct tee_ta_session *sess; 623 struct tee_obj *o = NULL; 624 struct tee_obj *attr_o = NULL; 625 char *file = NULL; 626 int fd = -1; 627 int fs_flags; 628 tee_fs_off_t off; 629 tee_fs_off_t e_off; 630 struct tee_pobj *po = NULL; 631 char *tmpfile = NULL; 632 int err = -1; 633 int filedoesnotexist; 634 struct user_ta_ctx *utc; 635 const struct tee_file_operations *fops = file_ops(storage_id); 636 size_t attr_size; 637 638 if (!fops) 639 return TEE_ERROR_ITEM_NOT_FOUND; 640 641 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 642 return TEE_ERROR_BAD_PARAMETERS; 643 644 res = tee_ta_get_current_session(&sess); 645 if (res != TEE_SUCCESS) 646 return res; 647 utc = to_user_ta_ctx(sess->ctx); 648 649 res = tee_mmu_check_access_rights(utc, 650 TEE_MEMORY_ACCESS_READ | 651 TEE_MEMORY_ACCESS_ANY_OWNER, 652 (tee_uaddr_t) object_id, 653 object_id_len); 654 if (res != TEE_SUCCESS) 655 goto err; 656 657 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 658 object_id_len, flags, fops, &po); 659 if (res != TEE_SUCCESS) 660 goto err; 661 662 /* check rights of the provided buffer */ 663 if (data && len) { 664 res = tee_mmu_check_access_rights(utc, 665 TEE_MEMORY_ACCESS_READ | 666 TEE_MEMORY_ACCESS_ANY_OWNER, 667 (tee_uaddr_t) data, len); 668 669 if (res != TEE_SUCCESS) 670 goto err; 671 } 672 673 o = tee_obj_alloc(); 674 if (o == NULL) { 675 res = TEE_ERROR_OUT_OF_MEMORY; 676 goto err; 677 } 678 679 o->info.handleFlags = 680 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 681 o->flags = flags; 682 o->pobj = po; 683 684 if (attr != TEE_HANDLE_NULL) { 685 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr), 686 &attr_o); 687 if (res != TEE_SUCCESS) 688 goto err; 689 } 690 691 res = tee_svc_storage_init_file(sess, o, attr_o, data, len); 692 if (res != TEE_SUCCESS) 693 goto err; 694 695 /* create persistent object filename */ 696 file = tee_svc_storage_create_filename(sess, object_id, 697 object_id_len, false); 698 if (file == NULL) { 699 res = TEE_ERROR_OUT_OF_MEMORY; 700 goto err; 701 } 702 703 filedoesnotexist = fops->access(file, TEE_FS_F_OK); 704 if (!filedoesnotexist) { 705 /* file exists */ 706 if (!(flags & TEE_DATA_FLAG_OVERWRITE)) { 707 res = TEE_ERROR_ACCESS_CONFLICT; 708 goto err; 709 } 710 } 711 712 /* create temporary persistent object filename */ 713 tmpfile = tee_svc_storage_create_filename(sess, object_id, 714 object_id_len, 715 true); 716 if (tmpfile == NULL) { 717 res = TEE_ERROR_OUT_OF_MEMORY; 718 goto err; 719 } 720 721 /* 722 * remove the file if it exists, because rename does not perform 723 * this operation. Note that it delete and rename should be atomic, 724 * which is not the case currently. 725 * Fixme: unlink must be removed once rename() support prior deletion 726 * of the new file name when it already exists. 727 */ 728 if (!filedoesnotexist) 729 fops->unlink(file); 730 /* rename temporary persistent object filename */ 731 err = fops->rename(tmpfile, file); 732 if (err) { 733 /* error codes needs better granularity */ 734 res = TEE_ERROR_GENERIC; 735 goto rmfile; 736 } 737 738 fs_flags = tee_svc_storage_conv_oflags(flags); 739 740 fd = fops->open(&errno, file, fs_flags); 741 if (fd < 0) { 742 res = errno; 743 goto err; 744 } 745 o->fd = fd; 746 747 tee_obj_add(utc, o); 748 749 res = tee_svc_copy_kaddr_to_uref(obj, o); 750 if (res != TEE_SUCCESS) 751 goto oclose; 752 753 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 754 if (res != TEE_SUCCESS) 755 goto oclose; 756 757 e_off = sizeof(struct tee_svc_storage_head) + attr_size; 758 off = fops->lseek(&errno, fd, e_off, TEE_FS_SEEK_SET); 759 if (off != e_off) { 760 res = TEE_ERROR_NO_DATA; 761 goto oclose; 762 } else { 763 res = TEE_SUCCESS; 764 } 765 766 goto exit; 767 768 oclose: 769 tee_obj_close(utc, o); 770 goto exit; 771 772 rmfile: 773 fops->unlink(tmpfile); 774 775 err: 776 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 777 res = TEE_ERROR_CORRUPT_OBJECT; 778 if (res == TEE_ERROR_CORRUPT_OBJECT && file) 779 fops->unlink(file); 780 if (fd >= 0) 781 fops->close(fd); 782 if (po) 783 tee_pobj_release(po); 784 if (o) 785 free(o); 786 787 exit: 788 free(file); 789 file = NULL; 790 free(tmpfile); 791 tmpfile = NULL; 792 793 return res; 794 } 795 796 TEE_Result syscall_storage_obj_del(unsigned long obj) 797 { 798 TEE_Result res; 799 struct tee_ta_session *sess; 800 struct tee_obj *o; 801 int err; 802 char *file; 803 char *dir; 804 struct user_ta_ctx *utc; 805 const struct tee_file_operations *fops; 806 807 res = tee_ta_get_current_session(&sess); 808 if (res != TEE_SUCCESS) 809 return res; 810 utc = to_user_ta_ctx(sess->ctx); 811 812 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 813 if (res != TEE_SUCCESS) 814 return res; 815 816 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 817 return TEE_ERROR_ACCESS_CONFLICT; 818 819 if (o->pobj == NULL || o->pobj->obj_id == NULL) 820 return TEE_ERROR_BAD_STATE; 821 822 file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 823 o->pobj->obj_id_len, false); 824 if (file == NULL) 825 return TEE_ERROR_OUT_OF_MEMORY; 826 827 fops = o->pobj->fops; 828 tee_obj_close(utc, o); 829 830 err = fops->access(file, TEE_FS_F_OK); 831 if (err) 832 /* file not found */ 833 return TEE_ERROR_STORAGE_NOT_AVAILABLE; 834 835 err = fops->unlink(file); 836 free(file); 837 if (err) 838 /* error codes needs better granularity */ 839 return TEE_ERROR_GENERIC; 840 841 /* try and remove dir */ 842 dir = tee_svc_storage_create_dirname(sess); 843 if (dir == NULL) 844 return TEE_ERROR_OUT_OF_MEMORY; 845 mutex_lock(&ta_dir_mutex); 846 /* ignore result */ 847 fops->rmdir(dir); 848 mutex_unlock(&ta_dir_mutex); 849 free(dir); 850 851 return TEE_SUCCESS; 852 } 853 854 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id, 855 size_t object_id_len) 856 { 857 TEE_Result res; 858 struct tee_ta_session *sess; 859 struct tee_obj *o; 860 struct tee_pobj *po = NULL; 861 char *new_file = NULL; 862 char *old_file = NULL; 863 int err = -1; 864 struct user_ta_ctx *utc; 865 const struct tee_file_operations *fops; 866 867 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 868 return TEE_ERROR_BAD_PARAMETERS; 869 870 res = tee_ta_get_current_session(&sess); 871 if (res != TEE_SUCCESS) 872 return res; 873 utc = to_user_ta_ctx(sess->ctx); 874 875 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 876 if (res != TEE_SUCCESS) 877 return res; 878 879 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 880 res = TEE_ERROR_BAD_STATE; 881 goto exit; 882 } 883 884 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { 885 res = TEE_ERROR_BAD_STATE; 886 goto exit; 887 } 888 889 if (o->pobj == NULL || o->pobj->obj_id == NULL) { 890 res = TEE_ERROR_BAD_STATE; 891 goto exit; 892 } 893 894 res = tee_mmu_check_access_rights(utc, 895 TEE_MEMORY_ACCESS_READ | 896 TEE_MEMORY_ACCESS_ANY_OWNER, 897 (tee_uaddr_t) object_id, object_id_len); 898 if (res != TEE_SUCCESS) 899 goto exit; 900 901 /* get new ds name */ 902 new_file = tee_svc_storage_create_filename(sess, object_id, 903 object_id_len, false); 904 if (new_file == NULL) { 905 res = TEE_ERROR_OUT_OF_MEMORY; 906 goto exit; 907 } 908 909 old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 910 o->pobj->obj_id_len, false); 911 if (old_file == NULL) { 912 res = TEE_ERROR_OUT_OF_MEMORY; 913 goto exit; 914 } 915 916 /* reserve dest name */ 917 fops = o->pobj->fops; 918 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 919 object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, 920 fops, &po); 921 if (res != TEE_SUCCESS) 922 goto exit; 923 924 err = fops->access(new_file, TEE_FS_F_OK); 925 if (err == 0) { 926 /* file exists */ 927 res = TEE_ERROR_ACCESS_CONFLICT; 928 goto exit; 929 } 930 931 /* move */ 932 err = fops->rename(old_file, new_file); 933 if (err) { 934 /* error codes needs better granularity */ 935 res = TEE_ERROR_GENERIC; 936 goto exit; 937 } 938 939 res = tee_pobj_rename(o->pobj, object_id, object_id_len); 940 941 exit: 942 tee_pobj_release(po); 943 944 free(new_file); 945 free(old_file); 946 947 return res; 948 } 949 950 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum) 951 { 952 struct tee_storage_enum *e; 953 struct tee_ta_session *sess; 954 TEE_Result res; 955 struct user_ta_ctx *utc; 956 957 if (obj_enum == NULL) 958 return TEE_ERROR_BAD_PARAMETERS; 959 960 res = tee_ta_get_current_session(&sess); 961 if (res != TEE_SUCCESS) 962 return res; 963 utc = to_user_ta_ctx(sess->ctx); 964 965 e = malloc(sizeof(struct tee_storage_enum)); 966 if (e == NULL) 967 return TEE_ERROR_OUT_OF_MEMORY; 968 969 e->dir = NULL; 970 e->fops = NULL; 971 TAILQ_INSERT_TAIL(&utc->storage_enums, e, link); 972 973 return tee_svc_copy_kaddr_to_uref(obj_enum, e); 974 } 975 976 TEE_Result syscall_storage_free_enum(unsigned long obj_enum) 977 { 978 struct tee_storage_enum *e; 979 TEE_Result res; 980 struct tee_ta_session *sess; 981 struct user_ta_ctx *utc; 982 983 res = tee_ta_get_current_session(&sess); 984 if (res != TEE_SUCCESS) 985 return res; 986 utc = to_user_ta_ctx(sess->ctx); 987 988 res = tee_svc_storage_get_enum(utc, 989 tee_svc_uref_to_vaddr(obj_enum), &e); 990 if (res != TEE_SUCCESS) 991 return res; 992 993 return tee_svc_close_enum(utc, e); 994 } 995 996 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum) 997 { 998 struct tee_storage_enum *e; 999 TEE_Result res; 1000 struct tee_ta_session *sess; 1001 1002 res = tee_ta_get_current_session(&sess); 1003 if (res != TEE_SUCCESS) 1004 return res; 1005 1006 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 1007 tee_svc_uref_to_vaddr(obj_enum), &e); 1008 if (res != TEE_SUCCESS) 1009 return res; 1010 1011 res = e->fops->closedir(e->dir); 1012 e->dir = NULL; 1013 if (res != 0) 1014 return TEE_ERROR_GENERIC; 1015 1016 return TEE_SUCCESS; 1017 } 1018 1019 static TEE_Result tee_svc_storage_set_enum(char *d_name, 1020 const struct tee_file_operations *fops, 1021 struct tee_obj *o) 1022 { 1023 TEE_Result res; 1024 uint32_t blen; 1025 uint32_t hslen; 1026 1027 o->info.handleFlags = 1028 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 1029 o->info.objectUsage = TEE_USAGE_DEFAULT; 1030 1031 hslen = strlen(d_name); 1032 blen = TEE_HS2B_BBUF_SIZE(hslen); 1033 o->pobj->obj_id = malloc(blen); 1034 if (!o->pobj->obj_id) { 1035 res = TEE_ERROR_OUT_OF_MEMORY; 1036 goto exit; 1037 } 1038 tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen); 1039 o->pobj->obj_id_len = blen; 1040 o->pobj->fops = fops; 1041 1042 res = TEE_SUCCESS; 1043 1044 exit: 1045 return res; 1046 1047 } 1048 1049 TEE_Result syscall_storage_start_enum(unsigned long obj_enum, 1050 unsigned long storage_id) 1051 { 1052 struct tee_storage_enum *e; 1053 char *dir; 1054 TEE_Result res; 1055 struct tee_ta_session *sess; 1056 struct tee_fs_dirent *d = NULL; 1057 struct tee_obj *o = NULL; 1058 const struct tee_file_operations *fops = file_ops(storage_id); 1059 1060 res = tee_ta_get_current_session(&sess); 1061 if (res != TEE_SUCCESS) 1062 return res; 1063 1064 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 1065 tee_svc_uref_to_vaddr(obj_enum), &e); 1066 if (res != TEE_SUCCESS) 1067 return res; 1068 1069 if (!fops) 1070 return TEE_ERROR_ITEM_NOT_FOUND; 1071 1072 dir = tee_svc_storage_create_dirname(sess); 1073 if (dir == NULL) 1074 return TEE_ERROR_OUT_OF_MEMORY; 1075 1076 e->fops = fops; 1077 e->dir = fops->opendir(dir); 1078 free(dir); 1079 if (e->dir == NULL) 1080 /* error codes needs better granularity */ 1081 return TEE_ERROR_ITEM_NOT_FOUND; 1082 1083 /* verify object */ 1084 o = tee_obj_alloc(); 1085 if (o == NULL) { 1086 res = TEE_ERROR_OUT_OF_MEMORY; 1087 goto exit; 1088 } 1089 1090 o->pobj = calloc(1, sizeof(struct tee_pobj)); 1091 if (!o->pobj) { 1092 res = TEE_ERROR_OUT_OF_MEMORY; 1093 goto exit; 1094 } 1095 1096 /* object enumeration loop */ 1097 do { 1098 d = fops->readdir(e->dir); 1099 if (d) { 1100 /* allocate obj_id and set object */ 1101 res = tee_svc_storage_set_enum(d->d_name, fops, o); 1102 if (res != TEE_SUCCESS) 1103 goto exit; 1104 res = tee_obj_verify(sess, o); 1105 if (res != TEE_SUCCESS) 1106 goto exit; 1107 /* free obj_id for each iteration */ 1108 free(o->pobj->obj_id); 1109 /* force obj_id to skip freeing at exit statement */ 1110 o->pobj->obj_id = NULL; 1111 } 1112 } while (d); 1113 1114 /* re-start */ 1115 res = fops->closedir(e->dir); 1116 e->dir = NULL; 1117 if (res != 0) { 1118 res = TEE_ERROR_GENERIC; 1119 goto exit; 1120 } 1121 1122 dir = tee_svc_storage_create_dirname(sess); 1123 if (dir == NULL) { 1124 res = TEE_ERROR_OUT_OF_MEMORY; 1125 goto exit; 1126 } 1127 1128 e->dir = fops->opendir(dir); 1129 free(dir); 1130 1131 exit: 1132 if (o) { 1133 if (o->pobj) 1134 free(o->pobj->obj_id); 1135 free(o->pobj); 1136 tee_obj_free(o); 1137 } 1138 1139 return res; 1140 } 1141 1142 TEE_Result syscall_storage_next_enum(unsigned long obj_enum, 1143 TEE_ObjectInfo *info, void *obj_id, uint64_t *len) 1144 { 1145 struct tee_storage_enum *e; 1146 struct tee_fs_dirent *d; 1147 TEE_Result res = TEE_SUCCESS; 1148 struct tee_ta_session *sess; 1149 struct tee_obj *o = NULL; 1150 uint64_t l; 1151 struct user_ta_ctx *utc; 1152 1153 res = tee_ta_get_current_session(&sess); 1154 if (res != TEE_SUCCESS) 1155 goto exit; 1156 utc = to_user_ta_ctx(sess->ctx); 1157 1158 res = tee_svc_storage_get_enum(utc, 1159 tee_svc_uref_to_vaddr(obj_enum), &e); 1160 if (res != TEE_SUCCESS) 1161 goto exit; 1162 1163 /* check rights of the provided buffers */ 1164 res = tee_mmu_check_access_rights(utc, 1165 TEE_MEMORY_ACCESS_WRITE | 1166 TEE_MEMORY_ACCESS_ANY_OWNER, 1167 (tee_uaddr_t) info, 1168 sizeof(TEE_ObjectInfo)); 1169 if (res != TEE_SUCCESS) 1170 goto exit; 1171 1172 res = tee_mmu_check_access_rights(utc, 1173 TEE_MEMORY_ACCESS_WRITE | 1174 TEE_MEMORY_ACCESS_ANY_OWNER, 1175 (tee_uaddr_t) obj_id, 1176 TEE_OBJECT_ID_MAX_LEN); 1177 if (res != TEE_SUCCESS) 1178 goto exit; 1179 1180 if (!e->fops) { 1181 res = TEE_ERROR_ITEM_NOT_FOUND; 1182 goto exit; 1183 } 1184 1185 d = e->fops->readdir(e->dir); 1186 if (d == NULL) { 1187 res = TEE_ERROR_ITEM_NOT_FOUND; 1188 goto exit; 1189 } 1190 1191 o = tee_obj_alloc(); 1192 if (o == NULL) { 1193 res = TEE_ERROR_OUT_OF_MEMORY; 1194 goto exit; 1195 } 1196 o->flags = TEE_DATA_FLAG_SHARE_READ; 1197 1198 o->pobj = calloc(1, sizeof(struct tee_pobj)); 1199 if (!o->pobj) { 1200 res = TEE_ERROR_OUT_OF_MEMORY; 1201 goto exit; 1202 } 1203 1204 res = tee_svc_storage_set_enum(d->d_name, e->fops, o); 1205 if (res != TEE_SUCCESS) 1206 goto exit; 1207 1208 res = tee_svc_storage_read_head(sess, o); 1209 if (res != TEE_SUCCESS) 1210 goto exit; 1211 1212 memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); 1213 memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); 1214 1215 l = o->pobj->obj_id_len; 1216 res = tee_svc_copy_to_user(len, &l, sizeof(*len)); 1217 1218 exit: 1219 if (o) { 1220 if (o->pobj) { 1221 if (o->fd >= 0) 1222 o->pobj->fops->close(o->fd); 1223 free(o->pobj->obj_id); 1224 } 1225 free(o->pobj); 1226 tee_obj_free(o); 1227 } 1228 1229 return res; 1230 } 1231 1232 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len, 1233 uint64_t *count) 1234 { 1235 TEE_Result res; 1236 TEE_Result errno; 1237 struct tee_ta_session *sess; 1238 struct tee_obj *o; 1239 int n_count; 1240 uint64_t u_count; 1241 struct user_ta_ctx *utc; 1242 1243 res = tee_ta_get_current_session(&sess); 1244 if (res != TEE_SUCCESS) 1245 goto exit; 1246 utc = to_user_ta_ctx(sess->ctx); 1247 1248 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 1249 if (res != TEE_SUCCESS) 1250 goto exit; 1251 1252 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1253 res = TEE_ERROR_BAD_STATE; 1254 goto exit; 1255 } 1256 1257 if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) { 1258 res = TEE_ERROR_ACCESS_CONFLICT; 1259 goto exit; 1260 } 1261 1262 /* check rights of the provided buffer */ 1263 res = tee_mmu_check_access_rights(utc, 1264 TEE_MEMORY_ACCESS_WRITE | 1265 TEE_MEMORY_ACCESS_ANY_OWNER, 1266 (tee_uaddr_t) data, len); 1267 if (res != TEE_SUCCESS) 1268 goto exit; 1269 1270 n_count = o->pobj->fops->read(&errno, o->fd, data, len); 1271 if (n_count < 0) { 1272 res = errno; 1273 EMSG("Error code=%x\n", (uint32_t)res); 1274 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1275 EMSG("Object corrupt\n"); 1276 tee_svc_storage_remove_corrupt_obj(sess, o); 1277 } 1278 goto exit; 1279 } 1280 u_count = (uint64_t)((n_count < 0) ? 0 : n_count); 1281 1282 res = tee_svc_copy_to_user(count, &u_count, sizeof(*count)); 1283 1284 o->info.dataPosition += u_count; 1285 1286 exit: 1287 return res; 1288 } 1289 1290 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len) 1291 { 1292 TEE_Result res; 1293 TEE_Result errno; 1294 struct tee_ta_session *sess; 1295 struct tee_obj *o; 1296 int err; 1297 struct user_ta_ctx *utc; 1298 1299 res = tee_ta_get_current_session(&sess); 1300 if (res != TEE_SUCCESS) 1301 goto exit; 1302 utc = to_user_ta_ctx(sess->ctx); 1303 1304 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 1305 if (res != TEE_SUCCESS) 1306 goto exit; 1307 1308 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1309 res = TEE_ERROR_BAD_STATE; 1310 goto exit; 1311 } 1312 1313 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1314 res = TEE_ERROR_ACCESS_CONFLICT; 1315 goto exit; 1316 } 1317 1318 /* check rights of the provided buffer */ 1319 res = tee_mmu_check_access_rights(utc, 1320 TEE_MEMORY_ACCESS_READ | 1321 TEE_MEMORY_ACCESS_ANY_OWNER, 1322 (tee_uaddr_t) data, len); 1323 if (res != TEE_SUCCESS) 1324 goto exit; 1325 1326 err = o->pobj->fops->write(&errno, o->fd, data, len); 1327 if (err < 0) 1328 res = errno; 1329 if (err != (int)len) 1330 goto exit; 1331 1332 o->info.dataPosition += len; 1333 if (o->info.dataPosition > o->info.dataSize) 1334 o->info.dataSize = o->info.dataPosition; 1335 1336 exit: 1337 return res; 1338 } 1339 1340 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len) 1341 { 1342 TEE_Result res; 1343 TEE_Result errno; 1344 struct tee_ta_session *sess; 1345 struct tee_obj *o; 1346 int err; 1347 tee_fs_off_t off; 1348 size_t attr_size; 1349 1350 res = tee_ta_get_current_session(&sess); 1351 if (res != TEE_SUCCESS) 1352 goto exit; 1353 1354 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 1355 tee_svc_uref_to_vaddr(obj), &o); 1356 if (res != TEE_SUCCESS) 1357 goto exit; 1358 1359 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1360 res = TEE_ERROR_BAD_STATE; 1361 goto exit; 1362 } 1363 1364 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1365 res = TEE_ERROR_ACCESS_CONFLICT; 1366 goto exit; 1367 } 1368 1369 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 1370 if (res != TEE_SUCCESS) 1371 goto exit; 1372 1373 off = sizeof(struct tee_svc_storage_head) + attr_size; 1374 err = o->pobj->fops->ftruncate(&errno, o->fd, len + off); 1375 if (err < 0) { 1376 res = errno; 1377 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1378 EMSG("Object corrupt\n"); 1379 res = tee_svc_storage_remove_corrupt_obj(sess, o); 1380 if (res != TEE_SUCCESS) 1381 goto exit; 1382 res = TEE_ERROR_CORRUPT_OBJECT; 1383 goto exit; 1384 } else 1385 res = TEE_ERROR_GENERIC; 1386 } 1387 1388 exit: 1389 return res; 1390 } 1391 1392 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset, 1393 unsigned long whence) 1394 { 1395 TEE_Result res; 1396 TEE_Result errno; 1397 struct tee_ta_session *sess; 1398 struct tee_obj *o; 1399 int fw; 1400 tee_fs_off_t off; 1401 tee_fs_off_t e_off = 0; 1402 size_t attr_size; 1403 1404 res = tee_ta_get_current_session(&sess); 1405 if (res != TEE_SUCCESS) 1406 goto exit; 1407 1408 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 1409 tee_svc_uref_to_vaddr(obj), &o); 1410 if (res != TEE_SUCCESS) 1411 goto exit; 1412 1413 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1414 res = TEE_ERROR_BAD_STATE; 1415 goto exit; 1416 } 1417 1418 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 1419 if (res != TEE_SUCCESS) 1420 goto exit; 1421 1422 fw = tee_svc_storage_conv_whence(whence); 1423 1424 if (whence == TEE_DATA_SEEK_SET) 1425 e_off = sizeof(struct tee_svc_storage_head) + attr_size; 1426 1427 off = o->pobj->fops->lseek(&errno, o->fd, e_off + offset, fw); 1428 if (off > -1 && off >= e_off) { 1429 res = TEE_SUCCESS; 1430 o->info.dataPosition = off - 1431 (sizeof(struct tee_svc_storage_head) + attr_size); 1432 } else { 1433 res = TEE_ERROR_GENERIC; 1434 goto exit; 1435 } 1436 1437 exit: 1438 return res; 1439 } 1440 1441 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc) 1442 { 1443 struct tee_storage_enum_head *eh = &utc->storage_enums; 1444 1445 /* disregard return value */ 1446 while (!TAILQ_EMPTY(eh)) 1447 tee_svc_close_enum(utc, TAILQ_FIRST(eh)); 1448 } 1449