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