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 assert(!o->fh); 271 res = fops->open(file, &o->fh); 272 if (res != TEE_SUCCESS) 273 goto exit; 274 275 /* read head */ 276 bytes = sizeof(struct tee_svc_storage_head); 277 res = fops->read(o->fh, &head, &bytes); 278 if (res != TEE_SUCCESS) { 279 if (res == TEE_ERROR_CORRUPT_OBJECT) 280 EMSG("Head corrupt\n"); 281 goto exit; 282 } 283 284 if (bytes != sizeof(struct tee_svc_storage_head)) { 285 res = TEE_ERROR_BAD_FORMAT; 286 goto exit; 287 } 288 289 res = tee_obj_set_type(o, head.objectType, head.maxKeySize); 290 if (res != TEE_SUCCESS) 291 goto exit; 292 293 if (head.meta_size) { 294 attr = malloc(head.meta_size); 295 if (!attr) { 296 res = TEE_ERROR_OUT_OF_MEMORY; 297 goto exit; 298 } 299 300 /* read meta */ 301 bytes = head.meta_size; 302 res = fops->read(o->fh, attr, &bytes); 303 if (res != TEE_SUCCESS || bytes != head.meta_size) { 304 res = TEE_ERROR_CORRUPT_OBJECT; 305 goto exit; 306 } 307 } 308 309 res = tee_obj_attr_from_binary(o, attr, head.meta_size); 310 if (res != TEE_SUCCESS) 311 goto exit; 312 313 o->info.dataSize = head.ds_size; 314 o->info.keySize = head.keySize; 315 o->info.objectUsage = head.objectUsage; 316 o->info.objectType = head.objectType; 317 o->have_attrs = head.have_attrs; 318 319 exit: 320 free(attr); 321 free(file); 322 323 return res; 324 } 325 326 327 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess, 328 struct tee_obj *o, 329 struct tee_obj *attr_o, void *data, 330 uint32_t len) 331 { 332 TEE_Result res = TEE_SUCCESS; 333 struct tee_svc_storage_head head; 334 char *tmpfile = NULL; 335 const struct tee_file_operations *fops; 336 void *attr = NULL; 337 size_t attr_size = 0; 338 339 if (o == NULL || o->pobj == NULL) 340 return TEE_ERROR_BAD_PARAMETERS; 341 342 fops = o->pobj->fops; 343 344 /* create temporary persistent object filename */ 345 tmpfile = tee_svc_storage_create_filename(sess, 346 o->pobj->obj_id, 347 o->pobj->obj_id_len, 348 true); 349 350 if (tmpfile == NULL) { 351 res = TEE_ERROR_OUT_OF_MEMORY; 352 goto exit; 353 } 354 355 res = tee_svc_storage_create_file(sess, tmpfile, fops, &o->fh); 356 if (res != TEE_SUCCESS) 357 goto exit; 358 359 if (attr_o) { 360 res = tee_obj_set_type(o, attr_o->info.objectType, 361 attr_o->info.maxKeySize); 362 if (res != TEE_SUCCESS) 363 goto exit; 364 res = tee_obj_attr_copy_from(o, attr_o); 365 if (res != TEE_SUCCESS) 366 goto exit; 367 o->have_attrs = attr_o->have_attrs; 368 o->info.objectUsage = attr_o->info.objectUsage; 369 o->info.keySize = attr_o->info.keySize; 370 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 371 if (res != TEE_SUCCESS) 372 goto exit; 373 if (attr_size) { 374 attr = malloc(attr_size); 375 if (!attr) { 376 res = TEE_ERROR_OUT_OF_MEMORY; 377 goto exit; 378 } 379 res = tee_obj_attr_to_binary(o, attr, &attr_size); 380 if (res != TEE_SUCCESS) 381 goto exit; 382 } 383 } else { 384 res = tee_obj_set_type(o, TEE_TYPE_DATA, 0); 385 if (res != TEE_SUCCESS) 386 goto exit; 387 } 388 389 /* write head */ 390 head.magic = TEE_SVC_STORAGE_MAGIC; 391 head.head_size = sizeof(struct tee_svc_storage_head); 392 head.meta_size = attr_size; 393 head.ds_size = len; 394 head.keySize = o->info.keySize; 395 head.maxKeySize = o->info.maxKeySize; 396 head.objectUsage = o->info.objectUsage; 397 head.objectType = o->info.objectType; 398 head.have_attrs = o->have_attrs; 399 400 /* write head */ 401 res = fops->write(o->fh, &head, sizeof(struct tee_svc_storage_head)); 402 if (res != TEE_SUCCESS) 403 goto exit; 404 405 /* write meta */ 406 res = fops->write(o->fh, attr, attr_size); 407 if (res != TEE_SUCCESS) 408 goto exit; 409 410 /* write init data */ 411 o->info.dataSize = len; 412 413 /* write data to fs if needed */ 414 if (data && len) 415 res = fops->write(o->fh, data, len); 416 417 exit: 418 free(attr); 419 free(tmpfile); 420 fops->close(&o->fh); 421 422 return res; 423 } 424 425 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id, 426 size_t object_id_len, unsigned long flags, 427 uint32_t *obj) 428 { 429 TEE_Result res; 430 struct tee_ta_session *sess; 431 struct tee_obj *o = NULL; 432 char *file = NULL; 433 struct tee_pobj *po = NULL; 434 struct user_ta_ctx *utc; 435 const struct tee_file_operations *fops = file_ops(storage_id); 436 size_t attr_size; 437 438 if (!fops) { 439 res = TEE_ERROR_ITEM_NOT_FOUND; 440 goto exit; 441 } 442 443 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) { 444 res = TEE_ERROR_BAD_PARAMETERS; 445 goto exit; 446 } 447 448 res = tee_ta_get_current_session(&sess); 449 if (res != TEE_SUCCESS) 450 goto err; 451 utc = to_user_ta_ctx(sess->ctx); 452 453 res = tee_mmu_check_access_rights(utc, 454 TEE_MEMORY_ACCESS_READ | 455 TEE_MEMORY_ACCESS_ANY_OWNER, 456 (uaddr_t) object_id, 457 object_id_len); 458 if (res != TEE_SUCCESS) 459 goto err; 460 461 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 462 object_id_len, flags, fops, &po); 463 if (res != TEE_SUCCESS) 464 goto err; 465 466 o = tee_obj_alloc(); 467 if (o == NULL) { 468 tee_pobj_release(po); 469 res = TEE_ERROR_OUT_OF_MEMORY; 470 goto err; 471 } 472 473 o->info.handleFlags = 474 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 475 o->flags = flags; 476 o->pobj = po; 477 tee_obj_add(utc, o); 478 479 res = tee_svc_storage_read_head(sess, o); 480 if (res != TEE_SUCCESS) { 481 if (res == TEE_ERROR_CORRUPT_OBJECT) { 482 EMSG("Object corrupt"); 483 goto err; 484 } 485 goto oclose; 486 } 487 488 res = tee_svc_copy_kaddr_to_uref(obj, o); 489 if (res != TEE_SUCCESS) 490 goto oclose; 491 492 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 493 if (res != TEE_SUCCESS) 494 goto oclose; 495 496 res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size, 497 TEE_DATA_SEEK_SET, NULL); 498 if (res != TEE_SUCCESS) 499 goto err; 500 501 goto exit; 502 503 oclose: 504 tee_obj_close(utc, o); 505 o = NULL; 506 507 err: 508 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 509 res = TEE_ERROR_CORRUPT_OBJECT; 510 if (res == TEE_ERROR_CORRUPT_OBJECT && o) 511 tee_svc_storage_remove_corrupt_obj(sess, o); 512 513 exit: 514 free(file); 515 file = NULL; 516 return res; 517 } 518 519 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id, 520 size_t object_id_len, unsigned long flags, 521 unsigned long attr, void *data, size_t len, 522 uint32_t *obj) 523 { 524 TEE_Result res; 525 struct tee_ta_session *sess; 526 struct tee_obj *o = NULL; 527 struct tee_obj *attr_o = NULL; 528 char *file = NULL; 529 struct tee_pobj *po = NULL; 530 char *tmpfile = NULL; 531 struct user_ta_ctx *utc; 532 const struct tee_file_operations *fops = file_ops(storage_id); 533 size_t attr_size; 534 535 if (!fops) 536 return TEE_ERROR_ITEM_NOT_FOUND; 537 538 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 539 return TEE_ERROR_BAD_PARAMETERS; 540 541 res = tee_ta_get_current_session(&sess); 542 if (res != TEE_SUCCESS) 543 return res; 544 utc = to_user_ta_ctx(sess->ctx); 545 546 res = tee_mmu_check_access_rights(utc, 547 TEE_MEMORY_ACCESS_READ | 548 TEE_MEMORY_ACCESS_ANY_OWNER, 549 (uaddr_t) object_id, 550 object_id_len); 551 if (res != TEE_SUCCESS) 552 goto err; 553 554 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 555 object_id_len, flags, fops, &po); 556 if (res != TEE_SUCCESS) 557 goto err; 558 559 /* check rights of the provided buffer */ 560 if (data && len) { 561 res = tee_mmu_check_access_rights(utc, 562 TEE_MEMORY_ACCESS_READ | 563 TEE_MEMORY_ACCESS_ANY_OWNER, 564 (uaddr_t) data, len); 565 566 if (res != TEE_SUCCESS) 567 goto err; 568 } 569 570 o = tee_obj_alloc(); 571 if (o == NULL) { 572 res = TEE_ERROR_OUT_OF_MEMORY; 573 goto err; 574 } 575 576 o->info.handleFlags = 577 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 578 o->flags = flags; 579 o->pobj = po; 580 581 if (attr != TEE_HANDLE_NULL) { 582 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr), 583 &attr_o); 584 if (res != TEE_SUCCESS) 585 goto err; 586 } 587 588 res = tee_svc_storage_init_file(sess, o, attr_o, data, len); 589 if (res != TEE_SUCCESS) 590 goto err; 591 592 /* create persistent object filename */ 593 file = tee_svc_storage_create_filename(sess, object_id, 594 object_id_len, false); 595 if (file == NULL) { 596 res = TEE_ERROR_OUT_OF_MEMORY; 597 goto err; 598 } 599 600 /* create temporary persistent object filename */ 601 tmpfile = tee_svc_storage_create_filename(sess, object_id, 602 object_id_len, 603 true); 604 if (tmpfile == NULL) { 605 res = TEE_ERROR_OUT_OF_MEMORY; 606 goto err; 607 } 608 609 /* rename temporary persistent object filename */ 610 res = fops->rename(tmpfile, file, !!(flags & TEE_DATA_FLAG_OVERWRITE)); 611 if (res != TEE_SUCCESS) 612 goto rmfile; 613 614 res = fops->open(file, &o->fh); 615 if (res != TEE_SUCCESS) 616 goto err; 617 618 tee_obj_add(utc, o); 619 620 res = tee_svc_copy_kaddr_to_uref(obj, o); 621 if (res != TEE_SUCCESS) 622 goto oclose; 623 624 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 625 if (res != TEE_SUCCESS) 626 goto oclose; 627 628 res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size, 629 TEE_DATA_SEEK_SET, NULL); 630 if (res != TEE_SUCCESS) 631 goto oclose; 632 633 goto exit; 634 635 oclose: 636 tee_obj_close(utc, o); 637 goto exit; 638 639 rmfile: 640 fops->remove(tmpfile); 641 642 err: 643 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 644 res = TEE_ERROR_CORRUPT_OBJECT; 645 if (res == TEE_ERROR_CORRUPT_OBJECT && file) 646 fops->remove(file); 647 if (o) 648 fops->close(&o->fh); 649 if (po) 650 tee_pobj_release(po); 651 free(o); 652 653 exit: 654 free(file); 655 free(tmpfile); 656 657 return res; 658 } 659 660 TEE_Result syscall_storage_obj_del(unsigned long obj) 661 { 662 TEE_Result res; 663 struct tee_ta_session *sess; 664 struct tee_obj *o; 665 char *file; 666 struct user_ta_ctx *utc; 667 const struct tee_file_operations *fops; 668 669 res = tee_ta_get_current_session(&sess); 670 if (res != TEE_SUCCESS) 671 return res; 672 utc = to_user_ta_ctx(sess->ctx); 673 674 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 675 if (res != TEE_SUCCESS) 676 return res; 677 678 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 679 return TEE_ERROR_ACCESS_CONFLICT; 680 681 if (o->pobj == NULL || o->pobj->obj_id == NULL) 682 return TEE_ERROR_BAD_STATE; 683 684 file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 685 o->pobj->obj_id_len, false); 686 if (file == NULL) 687 return TEE_ERROR_OUT_OF_MEMORY; 688 689 fops = o->pobj->fops; 690 tee_obj_close(utc, o); 691 692 res = fops->remove(file); 693 free(file); 694 return res; 695 } 696 697 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id, 698 size_t object_id_len) 699 { 700 TEE_Result res; 701 struct tee_ta_session *sess; 702 struct tee_obj *o; 703 struct tee_pobj *po = NULL; 704 char *new_file = NULL; 705 char *old_file = NULL; 706 struct user_ta_ctx *utc; 707 const struct tee_file_operations *fops; 708 709 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 710 return TEE_ERROR_BAD_PARAMETERS; 711 712 res = tee_ta_get_current_session(&sess); 713 if (res != TEE_SUCCESS) 714 return res; 715 utc = to_user_ta_ctx(sess->ctx); 716 717 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 718 if (res != TEE_SUCCESS) 719 return res; 720 721 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 722 res = TEE_ERROR_BAD_STATE; 723 goto exit; 724 } 725 726 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { 727 res = TEE_ERROR_BAD_STATE; 728 goto exit; 729 } 730 731 if (o->pobj == NULL || o->pobj->obj_id == NULL) { 732 res = TEE_ERROR_BAD_STATE; 733 goto exit; 734 } 735 736 res = tee_mmu_check_access_rights(utc, 737 TEE_MEMORY_ACCESS_READ | 738 TEE_MEMORY_ACCESS_ANY_OWNER, 739 (uaddr_t) object_id, object_id_len); 740 if (res != TEE_SUCCESS) 741 goto exit; 742 743 /* get new ds name */ 744 new_file = tee_svc_storage_create_filename(sess, object_id, 745 object_id_len, false); 746 if (new_file == NULL) { 747 res = TEE_ERROR_OUT_OF_MEMORY; 748 goto exit; 749 } 750 751 old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 752 o->pobj->obj_id_len, false); 753 if (old_file == NULL) { 754 res = TEE_ERROR_OUT_OF_MEMORY; 755 goto exit; 756 } 757 758 /* reserve dest name */ 759 fops = o->pobj->fops; 760 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 761 object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, 762 fops, &po); 763 if (res != TEE_SUCCESS) 764 goto exit; 765 766 /* move */ 767 res = fops->rename(old_file, new_file, false /* no overwrite */); 768 if (res == TEE_ERROR_GENERIC) 769 goto exit; 770 771 res = tee_pobj_rename(o->pobj, object_id, object_id_len); 772 773 exit: 774 tee_pobj_release(po); 775 776 free(new_file); 777 free(old_file); 778 779 return res; 780 } 781 782 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum) 783 { 784 struct tee_storage_enum *e; 785 struct tee_ta_session *sess; 786 TEE_Result res; 787 struct user_ta_ctx *utc; 788 789 if (obj_enum == NULL) 790 return TEE_ERROR_BAD_PARAMETERS; 791 792 res = tee_ta_get_current_session(&sess); 793 if (res != TEE_SUCCESS) 794 return res; 795 utc = to_user_ta_ctx(sess->ctx); 796 797 e = malloc(sizeof(struct tee_storage_enum)); 798 if (e == NULL) 799 return TEE_ERROR_OUT_OF_MEMORY; 800 801 e->dir = NULL; 802 e->fops = NULL; 803 TAILQ_INSERT_TAIL(&utc->storage_enums, e, link); 804 805 return tee_svc_copy_kaddr_to_uref(obj_enum, e); 806 } 807 808 TEE_Result syscall_storage_free_enum(unsigned long obj_enum) 809 { 810 struct tee_storage_enum *e; 811 TEE_Result res; 812 struct tee_ta_session *sess; 813 struct user_ta_ctx *utc; 814 815 res = tee_ta_get_current_session(&sess); 816 if (res != TEE_SUCCESS) 817 return res; 818 utc = to_user_ta_ctx(sess->ctx); 819 820 res = tee_svc_storage_get_enum(utc, 821 tee_svc_uref_to_vaddr(obj_enum), &e); 822 if (res != TEE_SUCCESS) 823 return res; 824 825 return tee_svc_close_enum(utc, e); 826 } 827 828 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum) 829 { 830 struct tee_storage_enum *e; 831 TEE_Result res; 832 struct tee_ta_session *sess; 833 834 res = tee_ta_get_current_session(&sess); 835 if (res != TEE_SUCCESS) 836 return res; 837 838 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 839 tee_svc_uref_to_vaddr(obj_enum), &e); 840 if (res != TEE_SUCCESS) 841 return res; 842 843 e->fops->closedir(e->dir); 844 e->dir = NULL; 845 846 return TEE_SUCCESS; 847 } 848 849 static TEE_Result tee_svc_storage_set_enum(char *d_name, 850 const struct tee_file_operations *fops, 851 struct tee_obj *o) 852 { 853 TEE_Result res; 854 uint32_t blen; 855 uint32_t hslen; 856 857 o->info.handleFlags = 858 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 859 o->info.objectUsage = TEE_USAGE_DEFAULT; 860 861 hslen = strlen(d_name); 862 blen = TEE_HS2B_BBUF_SIZE(hslen); 863 o->pobj->obj_id = malloc(blen); 864 if (!o->pobj->obj_id) { 865 res = TEE_ERROR_OUT_OF_MEMORY; 866 goto exit; 867 } 868 tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen); 869 o->pobj->obj_id_len = blen; 870 o->pobj->fops = fops; 871 872 res = TEE_SUCCESS; 873 874 exit: 875 return res; 876 877 } 878 879 TEE_Result syscall_storage_start_enum(unsigned long obj_enum, 880 unsigned long storage_id) 881 { 882 struct tee_storage_enum *e; 883 char *dir; 884 TEE_Result res; 885 struct tee_ta_session *sess; 886 const struct tee_file_operations *fops = file_ops(storage_id); 887 888 res = tee_ta_get_current_session(&sess); 889 if (res != TEE_SUCCESS) 890 return res; 891 892 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 893 tee_svc_uref_to_vaddr(obj_enum), &e); 894 if (res != TEE_SUCCESS) 895 return res; 896 897 if (!fops) 898 return TEE_ERROR_ITEM_NOT_FOUND; 899 900 e->fops = fops; 901 dir = tee_svc_storage_create_dirname(sess); 902 if (dir == NULL) { 903 res = TEE_ERROR_OUT_OF_MEMORY; 904 goto exit; 905 } 906 907 assert(!e->dir); 908 res = fops->opendir(dir, &e->dir); 909 free(dir); 910 exit: 911 return res; 912 } 913 914 TEE_Result syscall_storage_next_enum(unsigned long obj_enum, 915 TEE_ObjectInfo *info, void *obj_id, uint64_t *len) 916 { 917 struct tee_storage_enum *e; 918 struct tee_fs_dirent *d; 919 TEE_Result res = TEE_SUCCESS; 920 struct tee_ta_session *sess; 921 struct tee_obj *o = NULL; 922 uint64_t l; 923 struct user_ta_ctx *utc; 924 925 res = tee_ta_get_current_session(&sess); 926 if (res != TEE_SUCCESS) 927 goto exit; 928 utc = to_user_ta_ctx(sess->ctx); 929 930 res = tee_svc_storage_get_enum(utc, 931 tee_svc_uref_to_vaddr(obj_enum), &e); 932 if (res != TEE_SUCCESS) 933 goto exit; 934 935 /* check rights of the provided buffers */ 936 res = tee_mmu_check_access_rights(utc, 937 TEE_MEMORY_ACCESS_WRITE | 938 TEE_MEMORY_ACCESS_ANY_OWNER, 939 (uaddr_t) info, 940 sizeof(TEE_ObjectInfo)); 941 if (res != TEE_SUCCESS) 942 goto exit; 943 944 res = tee_mmu_check_access_rights(utc, 945 TEE_MEMORY_ACCESS_WRITE | 946 TEE_MEMORY_ACCESS_ANY_OWNER, 947 (uaddr_t) obj_id, 948 TEE_OBJECT_ID_MAX_LEN); 949 if (res != TEE_SUCCESS) 950 goto exit; 951 952 if (!e->fops) { 953 res = TEE_ERROR_ITEM_NOT_FOUND; 954 goto exit; 955 } 956 957 res = e->fops->readdir(e->dir, &d); 958 if (res != TEE_SUCCESS) 959 goto exit; 960 961 o = tee_obj_alloc(); 962 if (o == NULL) { 963 res = TEE_ERROR_OUT_OF_MEMORY; 964 goto exit; 965 } 966 o->flags = TEE_DATA_FLAG_SHARE_READ; 967 968 o->pobj = calloc(1, sizeof(struct tee_pobj)); 969 if (!o->pobj) { 970 res = TEE_ERROR_OUT_OF_MEMORY; 971 goto exit; 972 } 973 974 res = tee_svc_storage_set_enum(d->d_name, e->fops, o); 975 if (res != TEE_SUCCESS) 976 goto exit; 977 978 res = tee_svc_storage_read_head(sess, o); 979 if (res != TEE_SUCCESS) 980 goto exit; 981 982 memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); 983 memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); 984 985 l = o->pobj->obj_id_len; 986 res = tee_svc_copy_to_user(len, &l, sizeof(*len)); 987 988 exit: 989 if (o) { 990 if (o->pobj) { 991 o->pobj->fops->close(&o->fh); 992 free(o->pobj->obj_id); 993 } 994 free(o->pobj); 995 tee_obj_free(o); 996 } 997 998 return res; 999 } 1000 1001 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len, 1002 uint64_t *count) 1003 { 1004 TEE_Result res; 1005 struct tee_ta_session *sess; 1006 struct tee_obj *o; 1007 uint64_t u_count; 1008 struct user_ta_ctx *utc; 1009 size_t bytes; 1010 1011 res = tee_ta_get_current_session(&sess); 1012 if (res != TEE_SUCCESS) 1013 goto exit; 1014 utc = to_user_ta_ctx(sess->ctx); 1015 1016 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 1017 if (res != TEE_SUCCESS) 1018 goto exit; 1019 1020 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1021 res = TEE_ERROR_BAD_STATE; 1022 goto exit; 1023 } 1024 1025 if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) { 1026 res = TEE_ERROR_ACCESS_CONFLICT; 1027 goto exit; 1028 } 1029 1030 /* check rights of the provided buffer */ 1031 res = tee_mmu_check_access_rights(utc, 1032 TEE_MEMORY_ACCESS_WRITE | 1033 TEE_MEMORY_ACCESS_ANY_OWNER, 1034 (uaddr_t) data, len); 1035 if (res != TEE_SUCCESS) 1036 goto exit; 1037 1038 bytes = len; 1039 res = o->pobj->fops->read(o->fh, data, &bytes); 1040 if (res != TEE_SUCCESS) { 1041 EMSG("Error code=%x\n", (uint32_t)res); 1042 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1043 EMSG("Object corrupt\n"); 1044 tee_svc_storage_remove_corrupt_obj(sess, o); 1045 } 1046 goto exit; 1047 } 1048 1049 o->info.dataPosition += bytes; 1050 1051 u_count = bytes; 1052 res = tee_svc_copy_to_user(count, &u_count, sizeof(*count)); 1053 exit: 1054 return res; 1055 } 1056 1057 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len) 1058 { 1059 TEE_Result res; 1060 struct tee_ta_session *sess; 1061 struct tee_obj *o; 1062 struct user_ta_ctx *utc; 1063 1064 res = tee_ta_get_current_session(&sess); 1065 if (res != TEE_SUCCESS) 1066 goto exit; 1067 utc = to_user_ta_ctx(sess->ctx); 1068 1069 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 1070 if (res != TEE_SUCCESS) 1071 goto exit; 1072 1073 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1074 res = TEE_ERROR_BAD_STATE; 1075 goto exit; 1076 } 1077 1078 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1079 res = TEE_ERROR_ACCESS_CONFLICT; 1080 goto exit; 1081 } 1082 1083 /* check rights of the provided buffer */ 1084 res = tee_mmu_check_access_rights(utc, 1085 TEE_MEMORY_ACCESS_READ | 1086 TEE_MEMORY_ACCESS_ANY_OWNER, 1087 (uaddr_t) data, len); 1088 if (res != TEE_SUCCESS) 1089 goto exit; 1090 1091 res = o->pobj->fops->write(o->fh, data, len); 1092 if (res != TEE_SUCCESS) 1093 goto exit; 1094 1095 o->info.dataPosition += len; 1096 if (o->info.dataPosition > o->info.dataSize) 1097 o->info.dataSize = o->info.dataPosition; 1098 1099 exit: 1100 return res; 1101 } 1102 1103 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len) 1104 { 1105 TEE_Result res; 1106 struct tee_ta_session *sess; 1107 struct tee_obj *o; 1108 size_t off; 1109 size_t attr_size; 1110 1111 res = tee_ta_get_current_session(&sess); 1112 if (res != TEE_SUCCESS) 1113 goto exit; 1114 1115 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 1116 tee_svc_uref_to_vaddr(obj), &o); 1117 if (res != TEE_SUCCESS) 1118 goto exit; 1119 1120 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1121 res = TEE_ERROR_BAD_STATE; 1122 goto exit; 1123 } 1124 1125 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1126 res = TEE_ERROR_ACCESS_CONFLICT; 1127 goto exit; 1128 } 1129 1130 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 1131 if (res != TEE_SUCCESS) 1132 goto exit; 1133 1134 off = sizeof(struct tee_svc_storage_head) + attr_size; 1135 res = o->pobj->fops->truncate(o->fh, len + off); 1136 if (res != TEE_SUCCESS) { 1137 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1138 EMSG("Object corrupt\n"); 1139 res = tee_svc_storage_remove_corrupt_obj(sess, o); 1140 if (res != TEE_SUCCESS) 1141 goto exit; 1142 res = TEE_ERROR_CORRUPT_OBJECT; 1143 goto exit; 1144 } else 1145 res = TEE_ERROR_GENERIC; 1146 } 1147 1148 exit: 1149 return res; 1150 } 1151 1152 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset, 1153 unsigned long whence) 1154 { 1155 TEE_Result res; 1156 struct tee_ta_session *sess; 1157 struct tee_obj *o; 1158 int32_t off; 1159 size_t attr_size; 1160 1161 res = tee_ta_get_current_session(&sess); 1162 if (res != TEE_SUCCESS) 1163 goto exit; 1164 1165 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 1166 tee_svc_uref_to_vaddr(obj), &o); 1167 if (res != TEE_SUCCESS) 1168 goto exit; 1169 1170 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1171 res = TEE_ERROR_BAD_STATE; 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 = offset; 1180 if (whence == TEE_DATA_SEEK_SET) 1181 off += sizeof(struct tee_svc_storage_head) + attr_size; 1182 1183 res = o->pobj->fops->seek(o->fh, off, whence, &off); 1184 if (res != TEE_SUCCESS) 1185 goto exit; 1186 o->info.dataPosition = off - (sizeof(struct tee_svc_storage_head) + 1187 attr_size); 1188 1189 exit: 1190 return res; 1191 } 1192 1193 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc) 1194 { 1195 struct tee_storage_enum_head *eh = &utc->storage_enums; 1196 1197 /* disregard return value */ 1198 while (!TAILQ_EMPTY(eh)) 1199 tee_svc_close_enum(utc, TAILQ_FIRST(eh)); 1200 } 1201