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