1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <kernel/mutex.h> 30 #include <kernel/tee_misc.h> 31 #include <kernel/tee_ta_manager.h> 32 #include <mm/tee_mmu.h> 33 #include <string.h> 34 #include <tee_api_defines_extensions.h> 35 #include <tee_api_defines.h> 36 #include <tee/fs_dirfile.h> 37 #include <tee/tee_fs.h> 38 #include <tee/tee_obj.h> 39 #include <tee/tee_pobj.h> 40 #include <tee/tee_svc_cryp.h> 41 #include <tee/tee_svc.h> 42 #include <tee/tee_svc_storage.h> 43 #include <trace.h> 44 45 const struct tee_file_operations *tee_svc_storage_file_ops(uint32_t storage_id) 46 { 47 48 switch (storage_id) { 49 case TEE_STORAGE_PRIVATE: 50 #if defined(CFG_REE_FS) 51 return &ree_fs_ops; 52 #elif defined(CFG_RPMB_FS) 53 return &rpmb_fs_ops; 54 #else 55 #error At least one filesystem must be enabled. 56 #endif 57 #ifdef CFG_REE_FS 58 case TEE_STORAGE_PRIVATE_REE: 59 return &ree_fs_ops; 60 #endif 61 #ifdef CFG_RPMB_FS 62 case TEE_STORAGE_PRIVATE_RPMB: 63 return &rpmb_fs_ops; 64 #endif 65 default: 66 return NULL; 67 } 68 } 69 70 /* Header of GP formated secure storage files */ 71 struct tee_svc_storage_head { 72 uint32_t attr_size; 73 uint32_t keySize; 74 uint32_t maxKeySize; 75 uint32_t objectUsage; 76 uint32_t objectType; 77 uint32_t have_attrs; 78 }; 79 80 struct tee_storage_enum { 81 TAILQ_ENTRY(tee_storage_enum) link; 82 struct tee_fs_dir *dir; 83 const struct tee_file_operations *fops; 84 }; 85 86 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc, 87 uint32_t enum_id, 88 struct tee_storage_enum **e_out) 89 { 90 struct tee_storage_enum *e; 91 92 TAILQ_FOREACH(e, &utc->storage_enums, link) { 93 if (enum_id == (vaddr_t)e) { 94 *e_out = e; 95 return TEE_SUCCESS; 96 } 97 } 98 return TEE_ERROR_BAD_PARAMETERS; 99 } 100 101 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc, 102 struct tee_storage_enum *e) 103 { 104 if (e == NULL || utc == NULL) 105 return TEE_ERROR_BAD_PARAMETERS; 106 107 TAILQ_REMOVE(&utc->storage_enums, e, link); 108 109 if (e->fops) 110 e->fops->closedir(e->dir); 111 112 e->dir = NULL; 113 e->fops = NULL; 114 115 free(e); 116 117 return TEE_SUCCESS; 118 } 119 120 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */ 121 TEE_Result tee_svc_storage_create_filename(void *buf, size_t blen, 122 struct tee_pobj *po, bool transient) 123 { 124 uint8_t *file = buf; 125 uint32_t pos = 0; 126 uint32_t hslen = 1 /* Leading slash */ 127 + TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + po->obj_id_len) 128 + 1; /* Intermediate slash */ 129 130 /* +1 for the '.' (temporary persistent object) */ 131 if (transient) 132 hslen++; 133 134 if (blen < hslen) 135 return TEE_ERROR_SHORT_BUFFER; 136 137 file[pos++] = '/'; 138 pos += tee_b2hs((uint8_t *)&po->uuid, &file[pos], 139 sizeof(TEE_UUID), hslen); 140 file[pos++] = '/'; 141 142 if (transient) 143 file[pos++] = '.'; 144 145 tee_b2hs(po->obj_id, file + pos, po->obj_id_len, hslen - pos); 146 147 return TEE_SUCCESS; 148 } 149 150 #ifdef CFG_REE_FS 151 /* "/dirf.db" or "/<file number>" */ 152 TEE_Result 153 tee_svc_storage_create_filename_dfh(void *buf, size_t blen, 154 const struct tee_fs_dirfile_fileh *dfh) 155 { 156 char *file = buf; 157 size_t pos = 0; 158 size_t l; 159 160 if (pos >= blen) 161 return TEE_ERROR_SHORT_BUFFER; 162 163 file[pos] = '/'; 164 pos++; 165 if (pos >= blen) 166 return TEE_ERROR_SHORT_BUFFER; 167 168 l = blen - pos; 169 return tee_fs_dirfile_fileh_to_fname(dfh, file + pos, &l); 170 } 171 #endif 172 173 /* "/TA_uuid" */ 174 TEE_Result tee_svc_storage_create_dirname(void *buf, size_t blen, 175 const TEE_UUID *uuid) 176 { 177 uint8_t *dir = buf; 178 uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1; 179 180 if (blen < hslen) 181 return TEE_ERROR_SHORT_BUFFER; 182 183 dir[0] = '/'; 184 tee_b2hs((uint8_t *)uuid, dir + 1, sizeof(TEE_UUID), hslen); 185 186 return TEE_SUCCESS; 187 } 188 189 static TEE_Result tee_svc_storage_remove_corrupt_obj( 190 struct tee_ta_session *sess, 191 struct tee_obj *o) 192 { 193 o->pobj->fops->remove(o->pobj); 194 tee_obj_close(to_user_ta_ctx(sess->ctx), o); 195 196 return TEE_SUCCESS; 197 } 198 199 static TEE_Result tee_svc_storage_read_head(struct tee_obj *o) 200 { 201 TEE_Result res = TEE_SUCCESS; 202 size_t bytes; 203 struct tee_svc_storage_head head; 204 const struct tee_file_operations *fops = o->pobj->fops; 205 void *attr = NULL; 206 size_t size; 207 208 assert(!o->fh); 209 res = fops->open(o->pobj, &size, &o->fh); 210 if (res != TEE_SUCCESS) 211 goto exit; 212 213 /* read head */ 214 bytes = sizeof(struct tee_svc_storage_head); 215 res = fops->read(o->fh, 0, &head, &bytes); 216 if (res != TEE_SUCCESS) { 217 if (res == TEE_ERROR_CORRUPT_OBJECT) 218 EMSG("Head corrupt\n"); 219 goto exit; 220 } 221 222 if (bytes != sizeof(struct tee_svc_storage_head)) { 223 res = TEE_ERROR_BAD_FORMAT; 224 goto exit; 225 } 226 227 res = tee_obj_set_type(o, head.objectType, head.maxKeySize); 228 if (res != TEE_SUCCESS) 229 goto exit; 230 231 o->ds_pos = sizeof(struct tee_svc_storage_head) + head.attr_size; 232 if (head.attr_size) { 233 attr = malloc(head.attr_size); 234 if (!attr) { 235 res = TEE_ERROR_OUT_OF_MEMORY; 236 goto exit; 237 } 238 239 /* read meta */ 240 bytes = head.attr_size; 241 res = fops->read(o->fh, sizeof(struct tee_svc_storage_head), 242 attr, &bytes); 243 if (res != TEE_SUCCESS || bytes != head.attr_size) { 244 res = TEE_ERROR_CORRUPT_OBJECT; 245 goto exit; 246 } 247 } 248 249 res = tee_obj_attr_from_binary(o, attr, head.attr_size); 250 if (res != TEE_SUCCESS) 251 goto exit; 252 253 o->info.dataSize = size - sizeof(head) - head.attr_size; 254 o->info.keySize = head.keySize; 255 o->info.objectUsage = head.objectUsage; 256 o->info.objectType = head.objectType; 257 o->have_attrs = head.have_attrs; 258 259 exit: 260 free(attr); 261 262 return res; 263 } 264 265 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id, 266 size_t object_id_len, unsigned long flags, 267 uint32_t *obj) 268 { 269 TEE_Result res; 270 struct tee_ta_session *sess; 271 struct tee_obj *o = NULL; 272 char *file = NULL; 273 struct tee_pobj *po = NULL; 274 struct user_ta_ctx *utc; 275 size_t attr_size; 276 const struct tee_file_operations *fops = 277 tee_svc_storage_file_ops(storage_id); 278 279 if (!fops) { 280 res = TEE_ERROR_ITEM_NOT_FOUND; 281 goto exit; 282 } 283 284 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) { 285 res = TEE_ERROR_BAD_PARAMETERS; 286 goto exit; 287 } 288 289 res = tee_ta_get_current_session(&sess); 290 if (res != TEE_SUCCESS) 291 goto err; 292 utc = to_user_ta_ctx(sess->ctx); 293 294 res = tee_mmu_check_access_rights(utc, 295 TEE_MEMORY_ACCESS_READ, 296 (uaddr_t) object_id, 297 object_id_len); 298 if (res != TEE_SUCCESS) 299 goto err; 300 301 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 302 object_id_len, flags, false, fops, &po); 303 if (res != TEE_SUCCESS) 304 goto err; 305 306 o = tee_obj_alloc(); 307 if (o == NULL) { 308 tee_pobj_release(po); 309 res = TEE_ERROR_OUT_OF_MEMORY; 310 goto err; 311 } 312 313 o->info.handleFlags = 314 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 315 o->flags = flags; 316 o->pobj = po; 317 tee_obj_add(utc, o); 318 319 res = tee_svc_storage_read_head(o); 320 if (res != TEE_SUCCESS) { 321 if (res == TEE_ERROR_CORRUPT_OBJECT) { 322 EMSG("Object corrupt"); 323 goto err; 324 } 325 goto oclose; 326 } 327 328 res = tee_svc_copy_kaddr_to_uref(obj, o); 329 if (res != TEE_SUCCESS) 330 goto oclose; 331 332 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 333 if (res != TEE_SUCCESS) 334 goto oclose; 335 336 goto exit; 337 338 oclose: 339 tee_obj_close(utc, o); 340 o = NULL; 341 342 err: 343 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 344 res = TEE_ERROR_CORRUPT_OBJECT; 345 if (res == TEE_ERROR_CORRUPT_OBJECT && o) 346 tee_svc_storage_remove_corrupt_obj(sess, o); 347 348 exit: 349 free(file); 350 file = NULL; 351 return res; 352 } 353 354 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, 355 struct tee_obj *attr_o, void *data, 356 uint32_t len) 357 { 358 TEE_Result res = TEE_SUCCESS; 359 struct tee_svc_storage_head head; 360 const struct tee_file_operations *fops = o->pobj->fops; 361 void *attr = NULL; 362 size_t attr_size = 0; 363 364 if (attr_o) { 365 res = tee_obj_set_type(o, attr_o->info.objectType, 366 attr_o->info.maxKeySize); 367 if (res) 368 return res; 369 res = tee_obj_attr_copy_from(o, attr_o); 370 if (res) 371 return res; 372 o->have_attrs = attr_o->have_attrs; 373 o->info.objectUsage = attr_o->info.objectUsage; 374 o->info.keySize = attr_o->info.keySize; 375 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 376 if (res) 377 return res; 378 if (attr_size) { 379 attr = malloc(attr_size); 380 if (!attr) 381 return TEE_ERROR_OUT_OF_MEMORY; 382 res = tee_obj_attr_to_binary(o, attr, &attr_size); 383 if (res != TEE_SUCCESS) 384 goto exit; 385 } 386 } else { 387 res = tee_obj_set_type(o, TEE_TYPE_DATA, 0); 388 if (res != TEE_SUCCESS) 389 goto exit; 390 } 391 392 o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size; 393 394 /* write head */ 395 head.attr_size = attr_size; 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 res = fops->create(o->pobj, !!(o->flags & TEE_DATA_FLAG_OVERWRITE), 403 &head, sizeof(head), attr, attr_size, data, len, 404 &o->fh); 405 406 if (!res) 407 o->info.dataSize = len; 408 exit: 409 free(attr); 410 return res; 411 } 412 413 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id, 414 size_t object_id_len, unsigned long flags, 415 unsigned long attr, void *data, size_t len, 416 uint32_t *obj) 417 { 418 TEE_Result res; 419 struct tee_ta_session *sess; 420 struct tee_obj *o = NULL; 421 struct tee_obj *attr_o = NULL; 422 struct tee_pobj *po = NULL; 423 struct user_ta_ctx *utc; 424 const struct tee_file_operations *fops = 425 tee_svc_storage_file_ops(storage_id); 426 427 if (!fops) 428 return TEE_ERROR_ITEM_NOT_FOUND; 429 430 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 431 return TEE_ERROR_BAD_PARAMETERS; 432 433 res = tee_ta_get_current_session(&sess); 434 if (res != TEE_SUCCESS) 435 return res; 436 utc = to_user_ta_ctx(sess->ctx); 437 438 res = tee_mmu_check_access_rights(utc, 439 TEE_MEMORY_ACCESS_READ, 440 (uaddr_t) object_id, 441 object_id_len); 442 if (res != TEE_SUCCESS) 443 goto err; 444 445 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 446 object_id_len, flags, true, fops, &po); 447 if (res != TEE_SUCCESS) 448 goto err; 449 450 /* check rights of the provided buffer */ 451 if (data && len) { 452 res = tee_mmu_check_access_rights(utc, 453 TEE_MEMORY_ACCESS_READ | 454 TEE_MEMORY_ACCESS_ANY_OWNER, 455 (uaddr_t) data, len); 456 457 if (res != TEE_SUCCESS) 458 goto err; 459 } 460 461 o = tee_obj_alloc(); 462 if (o == NULL) { 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 472 if (attr != TEE_HANDLE_NULL) { 473 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr), 474 &attr_o); 475 if (res != TEE_SUCCESS) 476 goto err; 477 } 478 479 res = tee_svc_storage_init_file(o, attr_o, data, len); 480 if (res != TEE_SUCCESS) 481 goto err; 482 483 po = NULL; /* o owns it from now on */ 484 tee_obj_add(utc, o); 485 486 res = tee_svc_copy_kaddr_to_uref(obj, o); 487 if (res != TEE_SUCCESS) 488 goto oclose; 489 490 return TEE_SUCCESS; 491 492 oclose: 493 tee_obj_close(utc, o); 494 return res; 495 496 err: 497 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 498 res = TEE_ERROR_CORRUPT_OBJECT; 499 if (res == TEE_ERROR_CORRUPT_OBJECT && po) 500 fops->remove(po); 501 if (o) 502 fops->close(&o->fh); 503 if (po) 504 tee_pobj_release(po); 505 free(o); 506 507 return res; 508 } 509 510 TEE_Result syscall_storage_obj_del(unsigned long obj) 511 { 512 TEE_Result res; 513 struct tee_ta_session *sess; 514 struct tee_obj *o; 515 struct user_ta_ctx *utc; 516 517 res = tee_ta_get_current_session(&sess); 518 if (res != TEE_SUCCESS) 519 return res; 520 utc = to_user_ta_ctx(sess->ctx); 521 522 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 523 if (res != TEE_SUCCESS) 524 return res; 525 526 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 527 return TEE_ERROR_ACCESS_CONFLICT; 528 529 if (o->pobj == NULL || o->pobj->obj_id == NULL) 530 return TEE_ERROR_BAD_STATE; 531 532 res = o->pobj->fops->remove(o->pobj); 533 tee_obj_close(utc, o); 534 535 return res; 536 } 537 538 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id, 539 size_t object_id_len) 540 { 541 TEE_Result res; 542 struct tee_ta_session *sess; 543 struct tee_obj *o; 544 struct tee_pobj *po = NULL; 545 char *new_file = NULL; 546 char *old_file = NULL; 547 struct user_ta_ctx *utc; 548 const struct tee_file_operations *fops; 549 550 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 551 return TEE_ERROR_BAD_PARAMETERS; 552 553 res = tee_ta_get_current_session(&sess); 554 if (res != TEE_SUCCESS) 555 return res; 556 utc = to_user_ta_ctx(sess->ctx); 557 558 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 559 if (res != TEE_SUCCESS) 560 return res; 561 562 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 563 res = TEE_ERROR_BAD_STATE; 564 goto exit; 565 } 566 567 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { 568 res = TEE_ERROR_BAD_STATE; 569 goto exit; 570 } 571 572 if (o->pobj == NULL || o->pobj->obj_id == NULL) { 573 res = TEE_ERROR_BAD_STATE; 574 goto exit; 575 } 576 577 res = tee_mmu_check_access_rights(utc, 578 TEE_MEMORY_ACCESS_READ, 579 (uaddr_t) object_id, object_id_len); 580 if (res != TEE_SUCCESS) 581 goto exit; 582 583 /* reserve dest name */ 584 fops = o->pobj->fops; 585 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 586 object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, 587 false, fops, &po); 588 if (res != TEE_SUCCESS) 589 goto exit; 590 591 /* move */ 592 res = fops->rename(o->pobj, po, false /* no overwrite */); 593 if (res == TEE_ERROR_GENERIC) 594 goto exit; 595 596 res = tee_pobj_rename(o->pobj, object_id, object_id_len); 597 598 exit: 599 tee_pobj_release(po); 600 601 free(new_file); 602 free(old_file); 603 604 return res; 605 } 606 607 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum) 608 { 609 struct tee_storage_enum *e; 610 struct tee_ta_session *sess; 611 TEE_Result res; 612 struct user_ta_ctx *utc; 613 614 if (obj_enum == NULL) 615 return TEE_ERROR_BAD_PARAMETERS; 616 617 res = tee_ta_get_current_session(&sess); 618 if (res != TEE_SUCCESS) 619 return res; 620 utc = to_user_ta_ctx(sess->ctx); 621 622 e = malloc(sizeof(struct tee_storage_enum)); 623 if (e == NULL) 624 return TEE_ERROR_OUT_OF_MEMORY; 625 626 e->dir = NULL; 627 e->fops = NULL; 628 TAILQ_INSERT_TAIL(&utc->storage_enums, e, link); 629 630 return tee_svc_copy_kaddr_to_uref(obj_enum, e); 631 } 632 633 TEE_Result syscall_storage_free_enum(unsigned long obj_enum) 634 { 635 struct tee_storage_enum *e; 636 TEE_Result res; 637 struct tee_ta_session *sess; 638 struct user_ta_ctx *utc; 639 640 res = tee_ta_get_current_session(&sess); 641 if (res != TEE_SUCCESS) 642 return res; 643 utc = to_user_ta_ctx(sess->ctx); 644 645 res = tee_svc_storage_get_enum(utc, 646 tee_svc_uref_to_vaddr(obj_enum), &e); 647 if (res != TEE_SUCCESS) 648 return res; 649 650 return tee_svc_close_enum(utc, e); 651 } 652 653 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum) 654 { 655 struct tee_storage_enum *e; 656 TEE_Result res; 657 struct tee_ta_session *sess; 658 659 res = tee_ta_get_current_session(&sess); 660 if (res != TEE_SUCCESS) 661 return res; 662 663 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 664 tee_svc_uref_to_vaddr(obj_enum), &e); 665 if (res != TEE_SUCCESS) 666 return res; 667 668 if (e->fops) { 669 e->fops->closedir(e->dir); 670 e->fops = NULL; 671 e->dir = NULL; 672 } 673 assert(!e->dir); 674 675 return TEE_SUCCESS; 676 } 677 678 static TEE_Result tee_svc_storage_set_enum(struct tee_fs_dirent *d, 679 const struct tee_file_operations *fops, 680 struct tee_obj *o) 681 { 682 o->info.handleFlags = 683 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 684 o->info.objectUsage = TEE_USAGE_DEFAULT; 685 686 o->pobj->obj_id = malloc(d->oidlen); 687 if (!o->pobj->obj_id) 688 return TEE_ERROR_OUT_OF_MEMORY; 689 690 memcpy(o->pobj->obj_id, d->oid, d->oidlen); 691 o->pobj->obj_id_len = d->oidlen; 692 o->pobj->fops = fops; 693 694 return TEE_SUCCESS; 695 } 696 697 TEE_Result syscall_storage_start_enum(unsigned long obj_enum, 698 unsigned long storage_id) 699 { 700 struct tee_storage_enum *e; 701 TEE_Result res; 702 struct tee_ta_session *sess; 703 const struct tee_file_operations *fops = 704 tee_svc_storage_file_ops(storage_id); 705 706 res = tee_ta_get_current_session(&sess); 707 if (res != TEE_SUCCESS) 708 return res; 709 710 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 711 tee_svc_uref_to_vaddr(obj_enum), &e); 712 if (res != TEE_SUCCESS) 713 return res; 714 715 if (!fops) 716 return TEE_ERROR_ITEM_NOT_FOUND; 717 718 e->fops = fops; 719 assert(!e->dir); 720 return fops->opendir(&sess->ctx->uuid, &e->dir); 721 } 722 723 TEE_Result syscall_storage_next_enum(unsigned long obj_enum, 724 TEE_ObjectInfo *info, void *obj_id, uint64_t *len) 725 { 726 struct tee_storage_enum *e; 727 struct tee_fs_dirent *d; 728 TEE_Result res = TEE_SUCCESS; 729 struct tee_ta_session *sess; 730 struct tee_obj *o = NULL; 731 uint64_t l; 732 struct user_ta_ctx *utc; 733 734 res = tee_ta_get_current_session(&sess); 735 if (res != TEE_SUCCESS) 736 goto exit; 737 utc = to_user_ta_ctx(sess->ctx); 738 739 res = tee_svc_storage_get_enum(utc, 740 tee_svc_uref_to_vaddr(obj_enum), &e); 741 if (res != TEE_SUCCESS) 742 goto exit; 743 744 /* check rights of the provided buffers */ 745 res = tee_mmu_check_access_rights(utc, 746 TEE_MEMORY_ACCESS_WRITE | 747 TEE_MEMORY_ACCESS_ANY_OWNER, 748 (uaddr_t) info, 749 sizeof(TEE_ObjectInfo)); 750 if (res != TEE_SUCCESS) 751 goto exit; 752 753 res = tee_mmu_check_access_rights(utc, 754 TEE_MEMORY_ACCESS_WRITE | 755 TEE_MEMORY_ACCESS_ANY_OWNER, 756 (uaddr_t) obj_id, 757 TEE_OBJECT_ID_MAX_LEN); 758 if (res != TEE_SUCCESS) 759 goto exit; 760 761 if (!e->fops) { 762 res = TEE_ERROR_ITEM_NOT_FOUND; 763 goto exit; 764 } 765 766 res = e->fops->readdir(e->dir, &d); 767 if (res != TEE_SUCCESS) 768 goto exit; 769 770 o = tee_obj_alloc(); 771 if (o == NULL) { 772 res = TEE_ERROR_OUT_OF_MEMORY; 773 goto exit; 774 } 775 o->flags = TEE_DATA_FLAG_SHARE_READ; 776 777 o->pobj = calloc(1, sizeof(struct tee_pobj)); 778 if (!o->pobj) { 779 res = TEE_ERROR_OUT_OF_MEMORY; 780 goto exit; 781 } 782 783 o->pobj->uuid = sess->ctx->uuid; 784 res = tee_svc_storage_set_enum(d, e->fops, o); 785 if (res != TEE_SUCCESS) 786 goto exit; 787 788 res = tee_svc_storage_read_head(o); 789 if (res != TEE_SUCCESS) 790 goto exit; 791 792 memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); 793 memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); 794 795 l = o->pobj->obj_id_len; 796 res = tee_svc_copy_to_user(len, &l, sizeof(*len)); 797 798 exit: 799 if (o) { 800 if (o->pobj) { 801 o->pobj->fops->close(&o->fh); 802 free(o->pobj->obj_id); 803 } 804 free(o->pobj); 805 tee_obj_free(o); 806 } 807 808 return res; 809 } 810 811 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len, 812 uint64_t *count) 813 { 814 TEE_Result res; 815 struct tee_ta_session *sess; 816 struct tee_obj *o; 817 uint64_t u_count; 818 struct user_ta_ctx *utc; 819 size_t bytes; 820 821 res = tee_ta_get_current_session(&sess); 822 if (res != TEE_SUCCESS) 823 goto exit; 824 utc = to_user_ta_ctx(sess->ctx); 825 826 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 827 if (res != TEE_SUCCESS) 828 goto exit; 829 830 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 831 res = TEE_ERROR_BAD_STATE; 832 goto exit; 833 } 834 835 if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) { 836 res = TEE_ERROR_ACCESS_CONFLICT; 837 goto exit; 838 } 839 840 /* check rights of the provided buffer */ 841 res = tee_mmu_check_access_rights(utc, 842 TEE_MEMORY_ACCESS_WRITE | 843 TEE_MEMORY_ACCESS_ANY_OWNER, 844 (uaddr_t) data, len); 845 if (res != TEE_SUCCESS) 846 goto exit; 847 848 bytes = len; 849 res = o->pobj->fops->read(o->fh, o->ds_pos + o->info.dataPosition, 850 data, &bytes); 851 if (res != TEE_SUCCESS) { 852 EMSG("Error code=%x\n", (uint32_t)res); 853 if (res == TEE_ERROR_CORRUPT_OBJECT) { 854 EMSG("Object corrupt\n"); 855 tee_svc_storage_remove_corrupt_obj(sess, o); 856 } 857 goto exit; 858 } 859 860 o->info.dataPosition += bytes; 861 862 u_count = bytes; 863 res = tee_svc_copy_to_user(count, &u_count, sizeof(*count)); 864 exit: 865 return res; 866 } 867 868 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len) 869 { 870 TEE_Result res; 871 struct tee_ta_session *sess; 872 struct tee_obj *o; 873 struct user_ta_ctx *utc; 874 875 res = tee_ta_get_current_session(&sess); 876 if (res != TEE_SUCCESS) 877 goto exit; 878 utc = to_user_ta_ctx(sess->ctx); 879 880 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 881 if (res != TEE_SUCCESS) 882 goto exit; 883 884 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 885 res = TEE_ERROR_BAD_STATE; 886 goto exit; 887 } 888 889 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 890 res = TEE_ERROR_ACCESS_CONFLICT; 891 goto exit; 892 } 893 894 /* check rights of the provided buffer */ 895 res = tee_mmu_check_access_rights(utc, 896 TEE_MEMORY_ACCESS_READ | 897 TEE_MEMORY_ACCESS_ANY_OWNER, 898 (uaddr_t) data, len); 899 if (res != TEE_SUCCESS) 900 goto exit; 901 902 res = o->pobj->fops->write(o->fh, o->ds_pos + o->info.dataPosition, 903 data, len); 904 if (res != TEE_SUCCESS) 905 goto exit; 906 907 o->info.dataPosition += len; 908 if (o->info.dataPosition > o->info.dataSize) 909 o->info.dataSize = o->info.dataPosition; 910 911 exit: 912 return res; 913 } 914 915 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len) 916 { 917 TEE_Result res; 918 struct tee_ta_session *sess; 919 struct tee_obj *o; 920 size_t off; 921 size_t attr_size; 922 923 res = tee_ta_get_current_session(&sess); 924 if (res != TEE_SUCCESS) 925 goto exit; 926 927 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 928 tee_svc_uref_to_vaddr(obj), &o); 929 if (res != TEE_SUCCESS) 930 goto exit; 931 932 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 933 res = TEE_ERROR_BAD_STATE; 934 goto exit; 935 } 936 937 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 938 res = TEE_ERROR_ACCESS_CONFLICT; 939 goto exit; 940 } 941 942 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 943 if (res != TEE_SUCCESS) 944 goto exit; 945 946 off = sizeof(struct tee_svc_storage_head) + attr_size; 947 res = o->pobj->fops->truncate(o->fh, len + off); 948 if (res != TEE_SUCCESS) { 949 if (res == TEE_ERROR_CORRUPT_OBJECT) { 950 EMSG("Object corrupt\n"); 951 res = tee_svc_storage_remove_corrupt_obj(sess, o); 952 if (res != TEE_SUCCESS) 953 goto exit; 954 res = TEE_ERROR_CORRUPT_OBJECT; 955 goto exit; 956 } else 957 res = TEE_ERROR_GENERIC; 958 } 959 960 exit: 961 return res; 962 } 963 964 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset, 965 unsigned long whence) 966 { 967 TEE_Result res; 968 struct tee_ta_session *sess; 969 struct tee_obj *o; 970 size_t attr_size; 971 tee_fs_off_t new_pos; 972 973 res = tee_ta_get_current_session(&sess); 974 if (res != TEE_SUCCESS) 975 return res; 976 977 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 978 tee_svc_uref_to_vaddr(obj), &o); 979 if (res != TEE_SUCCESS) 980 return res; 981 982 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) 983 return TEE_ERROR_BAD_STATE; 984 985 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 986 if (res != TEE_SUCCESS) 987 return res; 988 989 switch (whence) { 990 case TEE_DATA_SEEK_SET: 991 new_pos = offset; 992 break; 993 case TEE_DATA_SEEK_CUR: 994 new_pos = o->info.dataPosition + offset; 995 break; 996 case TEE_DATA_SEEK_END: 997 new_pos = o->info.dataSize + offset; 998 break; 999 default: 1000 return TEE_ERROR_BAD_PARAMETERS; 1001 } 1002 1003 if (new_pos < 0) 1004 new_pos = 0; 1005 1006 if (new_pos > TEE_DATA_MAX_POSITION) { 1007 EMSG("Position is beyond TEE_DATA_MAX_POSITION"); 1008 return TEE_ERROR_BAD_PARAMETERS; 1009 } 1010 1011 o->info.dataPosition = new_pos; 1012 1013 return TEE_SUCCESS; 1014 } 1015 1016 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc) 1017 { 1018 struct tee_storage_enum_head *eh = &utc->storage_enums; 1019 1020 /* disregard return value */ 1021 while (!TAILQ_EMPTY(eh)) 1022 tee_svc_close_enum(utc, TAILQ_FIRST(eh)); 1023 } 1024