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