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