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