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 if (e == NULL || utc == NULL) 126 return TEE_ERROR_BAD_PARAMETERS; 127 128 TAILQ_REMOVE(&utc->storage_enums, e, link); 129 130 if (!e->fops) 131 return TEE_ERROR_ITEM_NOT_FOUND; 132 133 e->fops->closedir(e->dir); 134 e->dir = NULL; 135 e->fops = NULL; 136 137 free(e); 138 139 return TEE_SUCCESS; 140 } 141 142 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */ 143 char *tee_svc_storage_create_filename(struct tee_ta_session *sess, 144 void *object_id, 145 uint32_t object_id_len, 146 bool transient) 147 { 148 uint8_t *file; 149 uint32_t pos = 0; 150 uint32_t hslen = 1 /* Leading slash */ 151 + TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len) 152 + 1; /* Intermediate slash */ 153 154 /* +1 for the '.' (temporary persistent object) */ 155 if (transient) 156 hslen++; 157 158 file = malloc(hslen); 159 if (!file) 160 return NULL; 161 162 file[pos++] = '/'; 163 pos += tee_b2hs((uint8_t *)&sess->ctx->uuid, &file[pos], 164 sizeof(TEE_UUID), hslen); 165 file[pos++] = '/'; 166 167 if (transient) 168 file[pos++] = '.'; 169 170 tee_b2hs(object_id, file + pos, object_id_len, hslen - pos); 171 172 return (char *)file; 173 } 174 175 /* "/TA_uuid" */ 176 char *tee_svc_storage_create_dirname(struct tee_ta_session *sess) 177 { 178 uint8_t *dir; 179 uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1; 180 181 dir = malloc(hslen); 182 if (!dir) 183 return NULL; 184 185 dir[0] = '/'; 186 tee_b2hs((uint8_t *)&sess->ctx->uuid, dir + 1, sizeof(TEE_UUID), 187 hslen); 188 189 return (char *)dir; 190 } 191 192 static TEE_Result tee_svc_storage_remove_corrupt_obj( 193 struct tee_ta_session *sess, 194 struct tee_obj *o) 195 { 196 TEE_Result res; 197 char *file = NULL; 198 char *dir = NULL; 199 const struct tee_file_operations *fops = o->pobj->fops; 200 201 file = tee_svc_storage_create_filename(sess, 202 o->pobj->obj_id, 203 o->pobj->obj_id_len, 204 false); 205 if (file == NULL) { 206 res = TEE_ERROR_OUT_OF_MEMORY; 207 goto exit; 208 } 209 210 tee_obj_close(to_user_ta_ctx(sess->ctx), o); 211 fops->remove(file); 212 free(file); 213 dir = tee_svc_storage_create_dirname(sess); 214 if (dir != NULL) { 215 mutex_lock(&ta_dir_mutex); 216 fops->rmdir(dir); 217 mutex_unlock(&ta_dir_mutex); 218 free(dir); 219 } 220 221 res = TEE_SUCCESS; 222 223 exit: 224 return res; 225 } 226 227 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess, 228 char *file, 229 const struct tee_file_operations *fops, 230 struct tee_file_handle **fh) 231 { 232 TEE_Result res = TEE_SUCCESS; 233 char *dir = NULL; 234 int tmp; 235 int err; 236 237 assert(!*fh); 238 dir = tee_svc_storage_create_dirname(sess); 239 if (dir == NULL) { 240 res = TEE_ERROR_OUT_OF_MEMORY; 241 goto exit; 242 } 243 244 mutex_lock(&ta_dir_mutex); 245 246 /* try and make directory */ 247 err = fops->access(dir, TEE_FS_F_OK); 248 if (err) { 249 /* directory does not exists */ 250 tmp = fops->mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR | 251 TEE_FS_S_IXUSR); 252 253 if (tmp < 0) { 254 /* error codes needs better granularity */ 255 res = TEE_ERROR_GENERIC; 256 goto unlock; 257 } 258 } 259 260 /* try and open again */ 261 res = fops->create(file, true /* currently always overwrite */, fh); 262 263 unlock: 264 mutex_unlock(&ta_dir_mutex); 265 exit: 266 free(dir); 267 268 return res; 269 } 270 271 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess, 272 struct tee_obj *o) 273 { 274 TEE_Result res = TEE_SUCCESS; 275 size_t bytes; 276 struct tee_svc_storage_head head; 277 char *file = NULL; 278 const struct tee_file_operations *fops; 279 void *attr = NULL; 280 281 if (o == NULL || o->pobj == NULL) 282 return TEE_ERROR_BAD_PARAMETERS; 283 284 fops = o->pobj->fops; 285 286 file = tee_svc_storage_create_filename(sess, 287 o->pobj->obj_id, 288 o->pobj->obj_id_len, 289 false); 290 if (file == NULL) { 291 res = TEE_ERROR_OUT_OF_MEMORY; 292 goto exit; 293 } 294 295 if (fops->access(file, TEE_FS_F_OK)) { 296 /* file not found */ 297 res = TEE_ERROR_ITEM_NOT_FOUND; 298 goto exit; 299 } 300 301 assert(!o->fh); 302 res = fops->open(file, &o->fh); 303 if (res != TEE_SUCCESS) 304 goto exit; 305 306 /* read head */ 307 bytes = sizeof(struct tee_svc_storage_head); 308 res = fops->read(o->fh, &head, &bytes); 309 if (res != TEE_SUCCESS) { 310 if (res == TEE_ERROR_CORRUPT_OBJECT) 311 EMSG("Head corrupt\n"); 312 goto exit; 313 } 314 315 if (bytes != sizeof(struct tee_svc_storage_head)) { 316 res = TEE_ERROR_BAD_FORMAT; 317 goto exit; 318 } 319 320 res = tee_obj_set_type(o, head.objectType, head.maxKeySize); 321 if (res != TEE_SUCCESS) 322 goto exit; 323 324 if (head.meta_size) { 325 attr = malloc(head.meta_size); 326 if (!attr) { 327 res = TEE_ERROR_OUT_OF_MEMORY; 328 goto exit; 329 } 330 331 /* read meta */ 332 bytes = head.meta_size; 333 res = fops->read(o->fh, attr, &bytes); 334 if (res != TEE_SUCCESS || bytes != head.meta_size) { 335 res = TEE_ERROR_CORRUPT_OBJECT; 336 goto exit; 337 } 338 } 339 340 res = tee_obj_attr_from_binary(o, attr, head.meta_size); 341 if (res != TEE_SUCCESS) 342 goto exit; 343 344 o->info.dataSize = head.ds_size; 345 o->info.keySize = head.keySize; 346 o->info.objectUsage = head.objectUsage; 347 o->info.objectType = head.objectType; 348 o->have_attrs = head.have_attrs; 349 350 exit: 351 free(attr); 352 free(file); 353 354 return res; 355 } 356 357 358 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess, 359 struct tee_obj *o, 360 struct tee_obj *attr_o, void *data, 361 uint32_t len) 362 { 363 TEE_Result res = TEE_SUCCESS; 364 struct tee_svc_storage_head head; 365 char *tmpfile = NULL; 366 const struct tee_file_operations *fops; 367 void *attr = NULL; 368 size_t attr_size = 0; 369 370 if (o == NULL || o->pobj == NULL) 371 return TEE_ERROR_BAD_PARAMETERS; 372 373 fops = o->pobj->fops; 374 375 /* create temporary persistent object filename */ 376 tmpfile = tee_svc_storage_create_filename(sess, 377 o->pobj->obj_id, 378 o->pobj->obj_id_len, 379 true); 380 381 if (tmpfile == NULL) { 382 res = TEE_ERROR_OUT_OF_MEMORY; 383 goto exit; 384 } 385 386 res = tee_svc_storage_create_file(sess, tmpfile, fops, &o->fh); 387 if (res != TEE_SUCCESS) 388 goto exit; 389 390 if (attr_o) { 391 res = tee_obj_set_type(o, attr_o->info.objectType, 392 attr_o->info.maxKeySize); 393 if (res != TEE_SUCCESS) 394 goto exit; 395 res = tee_obj_attr_copy_from(o, attr_o); 396 if (res != TEE_SUCCESS) 397 goto exit; 398 o->have_attrs = attr_o->have_attrs; 399 o->info.objectUsage = attr_o->info.objectUsage; 400 o->info.keySize = attr_o->info.keySize; 401 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 402 if (res != TEE_SUCCESS) 403 goto exit; 404 if (attr_size) { 405 attr = malloc(attr_size); 406 if (!attr) { 407 res = TEE_ERROR_OUT_OF_MEMORY; 408 goto exit; 409 } 410 res = tee_obj_attr_to_binary(o, attr, &attr_size); 411 if (res != TEE_SUCCESS) 412 goto exit; 413 } 414 } else { 415 res = tee_obj_set_type(o, TEE_TYPE_DATA, 0); 416 if (res != TEE_SUCCESS) 417 goto exit; 418 } 419 420 /* write head */ 421 head.magic = TEE_SVC_STORAGE_MAGIC; 422 head.head_size = sizeof(struct tee_svc_storage_head); 423 head.meta_size = attr_size; 424 head.ds_size = len; 425 head.keySize = o->info.keySize; 426 head.maxKeySize = o->info.maxKeySize; 427 head.objectUsage = o->info.objectUsage; 428 head.objectType = o->info.objectType; 429 head.have_attrs = o->have_attrs; 430 431 /* write head */ 432 res = fops->write(o->fh, &head, sizeof(struct tee_svc_storage_head)); 433 if (res != TEE_SUCCESS) 434 goto exit; 435 436 /* write meta */ 437 res = fops->write(o->fh, attr, attr_size); 438 if (res != TEE_SUCCESS) 439 goto exit; 440 441 /* write init data */ 442 o->info.dataSize = len; 443 444 /* write data to fs if needed */ 445 if (data && len) 446 res = fops->write(o->fh, data, len); 447 448 exit: 449 free(attr); 450 free(tmpfile); 451 fops->close(&o->fh); 452 453 return res; 454 } 455 456 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id, 457 size_t object_id_len, unsigned long flags, 458 uint32_t *obj) 459 { 460 TEE_Result res; 461 struct tee_ta_session *sess; 462 struct tee_obj *o = NULL; 463 char *file = NULL; 464 struct tee_pobj *po = NULL; 465 struct user_ta_ctx *utc; 466 const struct tee_file_operations *fops = file_ops(storage_id); 467 size_t attr_size; 468 469 if (!fops) { 470 res = TEE_ERROR_ITEM_NOT_FOUND; 471 goto exit; 472 } 473 474 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) { 475 res = TEE_ERROR_BAD_PARAMETERS; 476 goto exit; 477 } 478 479 res = tee_ta_get_current_session(&sess); 480 if (res != TEE_SUCCESS) 481 goto err; 482 utc = to_user_ta_ctx(sess->ctx); 483 484 res = tee_mmu_check_access_rights(utc, 485 TEE_MEMORY_ACCESS_READ | 486 TEE_MEMORY_ACCESS_ANY_OWNER, 487 (tee_uaddr_t) object_id, 488 object_id_len); 489 if (res != TEE_SUCCESS) 490 goto err; 491 492 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 493 object_id_len, flags, fops, &po); 494 if (res != TEE_SUCCESS) 495 goto err; 496 497 o = tee_obj_alloc(); 498 if (o == NULL) { 499 tee_pobj_release(po); 500 res = TEE_ERROR_OUT_OF_MEMORY; 501 goto err; 502 } 503 504 o->info.handleFlags = 505 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 506 o->flags = flags; 507 o->pobj = po; 508 tee_obj_add(utc, o); 509 510 res = tee_svc_storage_read_head(sess, o); 511 if (res != TEE_SUCCESS) { 512 if (res == TEE_ERROR_CORRUPT_OBJECT) { 513 EMSG("Object corrupt"); 514 goto err; 515 } 516 goto oclose; 517 } 518 519 res = tee_svc_copy_kaddr_to_uref(obj, o); 520 if (res != TEE_SUCCESS) 521 goto oclose; 522 523 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 524 if (res != TEE_SUCCESS) 525 goto oclose; 526 527 res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size, 528 TEE_DATA_SEEK_SET, NULL); 529 if (res != TEE_SUCCESS) 530 goto err; 531 532 goto exit; 533 534 oclose: 535 tee_obj_close(utc, o); 536 o = NULL; 537 538 err: 539 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 540 res = TEE_ERROR_CORRUPT_OBJECT; 541 if (res == TEE_ERROR_CORRUPT_OBJECT && o) 542 tee_svc_storage_remove_corrupt_obj(sess, o); 543 544 exit: 545 free(file); 546 file = NULL; 547 return res; 548 } 549 550 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id, 551 size_t object_id_len, unsigned long flags, 552 unsigned long attr, void *data, size_t len, 553 uint32_t *obj) 554 { 555 TEE_Result res; 556 struct tee_ta_session *sess; 557 struct tee_obj *o = NULL; 558 struct tee_obj *attr_o = NULL; 559 char *file = NULL; 560 struct tee_pobj *po = NULL; 561 char *tmpfile = NULL; 562 int filedoesnotexist; 563 struct user_ta_ctx *utc; 564 const struct tee_file_operations *fops = file_ops(storage_id); 565 size_t attr_size; 566 567 if (!fops) 568 return TEE_ERROR_ITEM_NOT_FOUND; 569 570 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 571 return TEE_ERROR_BAD_PARAMETERS; 572 573 res = tee_ta_get_current_session(&sess); 574 if (res != TEE_SUCCESS) 575 return res; 576 utc = to_user_ta_ctx(sess->ctx); 577 578 res = tee_mmu_check_access_rights(utc, 579 TEE_MEMORY_ACCESS_READ | 580 TEE_MEMORY_ACCESS_ANY_OWNER, 581 (tee_uaddr_t) object_id, 582 object_id_len); 583 if (res != TEE_SUCCESS) 584 goto err; 585 586 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 587 object_id_len, flags, fops, &po); 588 if (res != TEE_SUCCESS) 589 goto err; 590 591 /* check rights of the provided buffer */ 592 if (data && len) { 593 res = tee_mmu_check_access_rights(utc, 594 TEE_MEMORY_ACCESS_READ | 595 TEE_MEMORY_ACCESS_ANY_OWNER, 596 (tee_uaddr_t) data, len); 597 598 if (res != TEE_SUCCESS) 599 goto err; 600 } 601 602 o = tee_obj_alloc(); 603 if (o == NULL) { 604 res = TEE_ERROR_OUT_OF_MEMORY; 605 goto err; 606 } 607 608 o->info.handleFlags = 609 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 610 o->flags = flags; 611 o->pobj = po; 612 613 if (attr != TEE_HANDLE_NULL) { 614 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr), 615 &attr_o); 616 if (res != TEE_SUCCESS) 617 goto err; 618 } 619 620 res = tee_svc_storage_init_file(sess, o, attr_o, data, len); 621 if (res != TEE_SUCCESS) 622 goto err; 623 624 /* create persistent object filename */ 625 file = tee_svc_storage_create_filename(sess, object_id, 626 object_id_len, false); 627 if (file == NULL) { 628 res = TEE_ERROR_OUT_OF_MEMORY; 629 goto err; 630 } 631 632 filedoesnotexist = fops->access(file, TEE_FS_F_OK); 633 if (!filedoesnotexist) { 634 /* file exists */ 635 if (!(flags & TEE_DATA_FLAG_OVERWRITE)) { 636 res = TEE_ERROR_ACCESS_CONFLICT; 637 goto err; 638 } 639 } 640 641 /* create temporary persistent object filename */ 642 tmpfile = tee_svc_storage_create_filename(sess, object_id, 643 object_id_len, 644 true); 645 if (tmpfile == NULL) { 646 res = TEE_ERROR_OUT_OF_MEMORY; 647 goto err; 648 } 649 650 /* 651 * remove the file if it exists, because rename does not perform 652 * this operation. Note that it delete and rename should be atomic, 653 * which is not the case currently. 654 * Fixme: unlink must be removed once rename() support prior deletion 655 * of the new file name when it already exists. 656 */ 657 if (!filedoesnotexist) 658 fops->remove(file); 659 /* rename temporary persistent object filename */ 660 res = fops->rename(tmpfile, file); 661 if (res != TEE_SUCCESS) 662 goto rmfile; 663 664 res = fops->open(file, &o->fh); 665 if (res != TEE_SUCCESS) 666 goto err; 667 668 tee_obj_add(utc, o); 669 670 res = tee_svc_copy_kaddr_to_uref(obj, o); 671 if (res != TEE_SUCCESS) 672 goto oclose; 673 674 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 675 if (res != TEE_SUCCESS) 676 goto oclose; 677 678 res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size, 679 TEE_DATA_SEEK_SET, NULL); 680 if (res != TEE_SUCCESS) 681 goto oclose; 682 683 goto exit; 684 685 oclose: 686 tee_obj_close(utc, o); 687 goto exit; 688 689 rmfile: 690 fops->remove(tmpfile); 691 692 err: 693 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 694 res = TEE_ERROR_CORRUPT_OBJECT; 695 if (res == TEE_ERROR_CORRUPT_OBJECT && file) 696 fops->remove(file); 697 if (o) 698 fops->close(&o->fh); 699 if (po) 700 tee_pobj_release(po); 701 free(o); 702 703 exit: 704 free(file); 705 free(tmpfile); 706 707 return res; 708 } 709 710 TEE_Result syscall_storage_obj_del(unsigned long obj) 711 { 712 TEE_Result res; 713 struct tee_ta_session *sess; 714 struct tee_obj *o; 715 int err; 716 char *file; 717 char *dir; 718 struct user_ta_ctx *utc; 719 const struct tee_file_operations *fops; 720 721 res = tee_ta_get_current_session(&sess); 722 if (res != TEE_SUCCESS) 723 return res; 724 utc = to_user_ta_ctx(sess->ctx); 725 726 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 727 if (res != TEE_SUCCESS) 728 return res; 729 730 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 731 return TEE_ERROR_ACCESS_CONFLICT; 732 733 if (o->pobj == NULL || o->pobj->obj_id == NULL) 734 return TEE_ERROR_BAD_STATE; 735 736 file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 737 o->pobj->obj_id_len, false); 738 if (file == NULL) 739 return TEE_ERROR_OUT_OF_MEMORY; 740 741 fops = o->pobj->fops; 742 tee_obj_close(utc, o); 743 744 err = fops->access(file, TEE_FS_F_OK); 745 if (err) 746 /* file not found */ 747 return TEE_ERROR_STORAGE_NOT_AVAILABLE; 748 749 res = fops->remove(file); 750 free(file); 751 if (res != TEE_SUCCESS) 752 return res; 753 754 /* try and remove dir */ 755 dir = tee_svc_storage_create_dirname(sess); 756 if (dir == NULL) 757 return TEE_ERROR_OUT_OF_MEMORY; 758 mutex_lock(&ta_dir_mutex); 759 /* ignore result */ 760 fops->rmdir(dir); 761 mutex_unlock(&ta_dir_mutex); 762 free(dir); 763 764 return TEE_SUCCESS; 765 } 766 767 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id, 768 size_t object_id_len) 769 { 770 TEE_Result res; 771 struct tee_ta_session *sess; 772 struct tee_obj *o; 773 struct tee_pobj *po = NULL; 774 char *new_file = NULL; 775 char *old_file = NULL; 776 int err = -1; 777 struct user_ta_ctx *utc; 778 const struct tee_file_operations *fops; 779 780 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 781 return TEE_ERROR_BAD_PARAMETERS; 782 783 res = tee_ta_get_current_session(&sess); 784 if (res != TEE_SUCCESS) 785 return res; 786 utc = to_user_ta_ctx(sess->ctx); 787 788 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 789 if (res != TEE_SUCCESS) 790 return res; 791 792 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 793 res = TEE_ERROR_BAD_STATE; 794 goto exit; 795 } 796 797 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { 798 res = TEE_ERROR_BAD_STATE; 799 goto exit; 800 } 801 802 if (o->pobj == NULL || o->pobj->obj_id == NULL) { 803 res = TEE_ERROR_BAD_STATE; 804 goto exit; 805 } 806 807 res = tee_mmu_check_access_rights(utc, 808 TEE_MEMORY_ACCESS_READ | 809 TEE_MEMORY_ACCESS_ANY_OWNER, 810 (tee_uaddr_t) object_id, object_id_len); 811 if (res != TEE_SUCCESS) 812 goto exit; 813 814 /* get new ds name */ 815 new_file = tee_svc_storage_create_filename(sess, object_id, 816 object_id_len, false); 817 if (new_file == NULL) { 818 res = TEE_ERROR_OUT_OF_MEMORY; 819 goto exit; 820 } 821 822 old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 823 o->pobj->obj_id_len, false); 824 if (old_file == NULL) { 825 res = TEE_ERROR_OUT_OF_MEMORY; 826 goto exit; 827 } 828 829 /* reserve dest name */ 830 fops = o->pobj->fops; 831 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 832 object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, 833 fops, &po); 834 if (res != TEE_SUCCESS) 835 goto exit; 836 837 err = fops->access(new_file, TEE_FS_F_OK); 838 if (err == 0) { 839 /* file exists */ 840 res = TEE_ERROR_ACCESS_CONFLICT; 841 goto exit; 842 } 843 844 /* move */ 845 err = fops->rename(old_file, new_file); 846 if (err) { 847 /* error codes needs better granularity */ 848 res = TEE_ERROR_GENERIC; 849 goto exit; 850 } 851 852 res = tee_pobj_rename(o->pobj, object_id, object_id_len); 853 854 exit: 855 tee_pobj_release(po); 856 857 free(new_file); 858 free(old_file); 859 860 return res; 861 } 862 863 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum) 864 { 865 struct tee_storage_enum *e; 866 struct tee_ta_session *sess; 867 TEE_Result res; 868 struct user_ta_ctx *utc; 869 870 if (obj_enum == NULL) 871 return TEE_ERROR_BAD_PARAMETERS; 872 873 res = tee_ta_get_current_session(&sess); 874 if (res != TEE_SUCCESS) 875 return res; 876 utc = to_user_ta_ctx(sess->ctx); 877 878 e = malloc(sizeof(struct tee_storage_enum)); 879 if (e == NULL) 880 return TEE_ERROR_OUT_OF_MEMORY; 881 882 e->dir = NULL; 883 e->fops = NULL; 884 TAILQ_INSERT_TAIL(&utc->storage_enums, e, link); 885 886 return tee_svc_copy_kaddr_to_uref(obj_enum, e); 887 } 888 889 TEE_Result syscall_storage_free_enum(unsigned long obj_enum) 890 { 891 struct tee_storage_enum *e; 892 TEE_Result res; 893 struct tee_ta_session *sess; 894 struct user_ta_ctx *utc; 895 896 res = tee_ta_get_current_session(&sess); 897 if (res != TEE_SUCCESS) 898 return res; 899 utc = to_user_ta_ctx(sess->ctx); 900 901 res = tee_svc_storage_get_enum(utc, 902 tee_svc_uref_to_vaddr(obj_enum), &e); 903 if (res != TEE_SUCCESS) 904 return res; 905 906 return tee_svc_close_enum(utc, e); 907 } 908 909 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum) 910 { 911 struct tee_storage_enum *e; 912 TEE_Result res; 913 struct tee_ta_session *sess; 914 915 res = tee_ta_get_current_session(&sess); 916 if (res != TEE_SUCCESS) 917 return res; 918 919 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 920 tee_svc_uref_to_vaddr(obj_enum), &e); 921 if (res != TEE_SUCCESS) 922 return res; 923 924 e->fops->closedir(e->dir); 925 e->dir = NULL; 926 927 return TEE_SUCCESS; 928 } 929 930 static TEE_Result tee_svc_storage_set_enum(char *d_name, 931 const struct tee_file_operations *fops, 932 struct tee_obj *o) 933 { 934 TEE_Result res; 935 uint32_t blen; 936 uint32_t hslen; 937 938 o->info.handleFlags = 939 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 940 o->info.objectUsage = TEE_USAGE_DEFAULT; 941 942 hslen = strlen(d_name); 943 blen = TEE_HS2B_BBUF_SIZE(hslen); 944 o->pobj->obj_id = malloc(blen); 945 if (!o->pobj->obj_id) { 946 res = TEE_ERROR_OUT_OF_MEMORY; 947 goto exit; 948 } 949 tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen); 950 o->pobj->obj_id_len = blen; 951 o->pobj->fops = fops; 952 953 res = TEE_SUCCESS; 954 955 exit: 956 return res; 957 958 } 959 960 TEE_Result syscall_storage_start_enum(unsigned long obj_enum, 961 unsigned long storage_id) 962 { 963 struct tee_storage_enum *e; 964 char *dir; 965 TEE_Result res; 966 struct tee_ta_session *sess; 967 const struct tee_file_operations *fops = file_ops(storage_id); 968 969 res = tee_ta_get_current_session(&sess); 970 if (res != TEE_SUCCESS) 971 return res; 972 973 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 974 tee_svc_uref_to_vaddr(obj_enum), &e); 975 if (res != TEE_SUCCESS) 976 return res; 977 978 if (!fops) 979 return TEE_ERROR_ITEM_NOT_FOUND; 980 981 e->fops = fops; 982 dir = tee_svc_storage_create_dirname(sess); 983 if (dir == NULL) { 984 res = TEE_ERROR_OUT_OF_MEMORY; 985 goto exit; 986 } 987 988 assert(!e->dir); 989 res = fops->opendir(dir, &e->dir); 990 free(dir); 991 exit: 992 return res; 993 } 994 995 TEE_Result syscall_storage_next_enum(unsigned long obj_enum, 996 TEE_ObjectInfo *info, void *obj_id, uint64_t *len) 997 { 998 struct tee_storage_enum *e; 999 struct tee_fs_dirent *d; 1000 TEE_Result res = TEE_SUCCESS; 1001 struct tee_ta_session *sess; 1002 struct tee_obj *o = NULL; 1003 uint64_t l; 1004 struct user_ta_ctx *utc; 1005 1006 res = tee_ta_get_current_session(&sess); 1007 if (res != TEE_SUCCESS) 1008 goto exit; 1009 utc = to_user_ta_ctx(sess->ctx); 1010 1011 res = tee_svc_storage_get_enum(utc, 1012 tee_svc_uref_to_vaddr(obj_enum), &e); 1013 if (res != TEE_SUCCESS) 1014 goto exit; 1015 1016 /* check rights of the provided buffers */ 1017 res = tee_mmu_check_access_rights(utc, 1018 TEE_MEMORY_ACCESS_WRITE | 1019 TEE_MEMORY_ACCESS_ANY_OWNER, 1020 (tee_uaddr_t) info, 1021 sizeof(TEE_ObjectInfo)); 1022 if (res != TEE_SUCCESS) 1023 goto exit; 1024 1025 res = tee_mmu_check_access_rights(utc, 1026 TEE_MEMORY_ACCESS_WRITE | 1027 TEE_MEMORY_ACCESS_ANY_OWNER, 1028 (tee_uaddr_t) obj_id, 1029 TEE_OBJECT_ID_MAX_LEN); 1030 if (res != TEE_SUCCESS) 1031 goto exit; 1032 1033 if (!e->fops) { 1034 res = TEE_ERROR_ITEM_NOT_FOUND; 1035 goto exit; 1036 } 1037 1038 res = e->fops->readdir(e->dir, &d); 1039 if (res != TEE_SUCCESS) 1040 goto exit; 1041 1042 o = tee_obj_alloc(); 1043 if (o == NULL) { 1044 res = TEE_ERROR_OUT_OF_MEMORY; 1045 goto exit; 1046 } 1047 o->flags = TEE_DATA_FLAG_SHARE_READ; 1048 1049 o->pobj = calloc(1, sizeof(struct tee_pobj)); 1050 if (!o->pobj) { 1051 res = TEE_ERROR_OUT_OF_MEMORY; 1052 goto exit; 1053 } 1054 1055 res = tee_svc_storage_set_enum(d->d_name, e->fops, o); 1056 if (res != TEE_SUCCESS) 1057 goto exit; 1058 1059 res = tee_svc_storage_read_head(sess, o); 1060 if (res != TEE_SUCCESS) 1061 goto exit; 1062 1063 memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); 1064 memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); 1065 1066 l = o->pobj->obj_id_len; 1067 res = tee_svc_copy_to_user(len, &l, sizeof(*len)); 1068 1069 exit: 1070 if (o) { 1071 if (o->pobj) { 1072 o->pobj->fops->close(&o->fh); 1073 free(o->pobj->obj_id); 1074 } 1075 free(o->pobj); 1076 tee_obj_free(o); 1077 } 1078 1079 return res; 1080 } 1081 1082 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len, 1083 uint64_t *count) 1084 { 1085 TEE_Result res; 1086 struct tee_ta_session *sess; 1087 struct tee_obj *o; 1088 uint64_t u_count; 1089 struct user_ta_ctx *utc; 1090 size_t bytes; 1091 1092 res = tee_ta_get_current_session(&sess); 1093 if (res != TEE_SUCCESS) 1094 goto exit; 1095 utc = to_user_ta_ctx(sess->ctx); 1096 1097 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 1098 if (res != TEE_SUCCESS) 1099 goto exit; 1100 1101 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1102 res = TEE_ERROR_BAD_STATE; 1103 goto exit; 1104 } 1105 1106 if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) { 1107 res = TEE_ERROR_ACCESS_CONFLICT; 1108 goto exit; 1109 } 1110 1111 /* check rights of the provided buffer */ 1112 res = tee_mmu_check_access_rights(utc, 1113 TEE_MEMORY_ACCESS_WRITE | 1114 TEE_MEMORY_ACCESS_ANY_OWNER, 1115 (tee_uaddr_t) data, len); 1116 if (res != TEE_SUCCESS) 1117 goto exit; 1118 1119 bytes = len; 1120 res = o->pobj->fops->read(o->fh, data, &bytes); 1121 if (res != TEE_SUCCESS) { 1122 EMSG("Error code=%x\n", (uint32_t)res); 1123 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1124 EMSG("Object corrupt\n"); 1125 tee_svc_storage_remove_corrupt_obj(sess, o); 1126 } 1127 goto exit; 1128 } 1129 1130 o->info.dataPosition += bytes; 1131 1132 u_count = bytes; 1133 res = tee_svc_copy_to_user(count, &u_count, sizeof(*count)); 1134 exit: 1135 return res; 1136 } 1137 1138 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len) 1139 { 1140 TEE_Result res; 1141 struct tee_ta_session *sess; 1142 struct tee_obj *o; 1143 struct user_ta_ctx *utc; 1144 1145 res = tee_ta_get_current_session(&sess); 1146 if (res != TEE_SUCCESS) 1147 goto exit; 1148 utc = to_user_ta_ctx(sess->ctx); 1149 1150 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 1151 if (res != TEE_SUCCESS) 1152 goto exit; 1153 1154 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1155 res = TEE_ERROR_BAD_STATE; 1156 goto exit; 1157 } 1158 1159 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1160 res = TEE_ERROR_ACCESS_CONFLICT; 1161 goto exit; 1162 } 1163 1164 /* check rights of the provided buffer */ 1165 res = tee_mmu_check_access_rights(utc, 1166 TEE_MEMORY_ACCESS_READ | 1167 TEE_MEMORY_ACCESS_ANY_OWNER, 1168 (tee_uaddr_t) data, len); 1169 if (res != TEE_SUCCESS) 1170 goto exit; 1171 1172 res = o->pobj->fops->write(o->fh, data, len); 1173 if (res != TEE_SUCCESS) 1174 goto exit; 1175 1176 o->info.dataPosition += len; 1177 if (o->info.dataPosition > o->info.dataSize) 1178 o->info.dataSize = o->info.dataPosition; 1179 1180 exit: 1181 return res; 1182 } 1183 1184 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len) 1185 { 1186 TEE_Result res; 1187 struct tee_ta_session *sess; 1188 struct tee_obj *o; 1189 size_t off; 1190 size_t attr_size; 1191 1192 res = tee_ta_get_current_session(&sess); 1193 if (res != TEE_SUCCESS) 1194 goto exit; 1195 1196 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 1197 tee_svc_uref_to_vaddr(obj), &o); 1198 if (res != TEE_SUCCESS) 1199 goto exit; 1200 1201 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1202 res = TEE_ERROR_BAD_STATE; 1203 goto exit; 1204 } 1205 1206 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1207 res = TEE_ERROR_ACCESS_CONFLICT; 1208 goto exit; 1209 } 1210 1211 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 1212 if (res != TEE_SUCCESS) 1213 goto exit; 1214 1215 off = sizeof(struct tee_svc_storage_head) + attr_size; 1216 res = o->pobj->fops->truncate(o->fh, len + off); 1217 if (res != TEE_SUCCESS) { 1218 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1219 EMSG("Object corrupt\n"); 1220 res = tee_svc_storage_remove_corrupt_obj(sess, o); 1221 if (res != TEE_SUCCESS) 1222 goto exit; 1223 res = TEE_ERROR_CORRUPT_OBJECT; 1224 goto exit; 1225 } else 1226 res = TEE_ERROR_GENERIC; 1227 } 1228 1229 exit: 1230 return res; 1231 } 1232 1233 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset, 1234 unsigned long whence) 1235 { 1236 TEE_Result res; 1237 struct tee_ta_session *sess; 1238 struct tee_obj *o; 1239 int32_t off; 1240 size_t attr_size; 1241 1242 res = tee_ta_get_current_session(&sess); 1243 if (res != TEE_SUCCESS) 1244 goto exit; 1245 1246 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 1247 tee_svc_uref_to_vaddr(obj), &o); 1248 if (res != TEE_SUCCESS) 1249 goto exit; 1250 1251 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1252 res = TEE_ERROR_BAD_STATE; 1253 goto exit; 1254 } 1255 1256 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 1257 if (res != TEE_SUCCESS) 1258 goto exit; 1259 1260 off = offset; 1261 if (whence == TEE_DATA_SEEK_SET) 1262 off += sizeof(struct tee_svc_storage_head) + attr_size; 1263 1264 res = o->pobj->fops->seek(o->fh, off, whence, &off); 1265 if (res != TEE_SUCCESS) 1266 goto exit; 1267 o->info.dataPosition = off - (sizeof(struct tee_svc_storage_head) + 1268 attr_size); 1269 1270 exit: 1271 return res; 1272 } 1273 1274 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc) 1275 { 1276 struct tee_storage_enum_head *eh = &utc->storage_enums; 1277 1278 /* disregard return value */ 1279 while (!TAILQ_EMPTY(eh)) 1280 tee_svc_close_enum(utc, TAILQ_FIRST(eh)); 1281 } 1282