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