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