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 const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ | 260 TEE_DATA_FLAG_ACCESS_WRITE | 261 TEE_DATA_FLAG_ACCESS_WRITE_META | 262 TEE_DATA_FLAG_SHARE_READ | 263 TEE_DATA_FLAG_SHARE_WRITE; 264 const struct tee_file_operations *fops = 265 tee_svc_storage_file_ops(storage_id); 266 struct tee_ta_session *sess = NULL; 267 struct user_ta_ctx *utc = NULL; 268 TEE_Result res = TEE_SUCCESS; 269 struct tee_pobj *po = NULL; 270 struct tee_obj *o = NULL; 271 char *file = NULL; 272 273 if (flags & ~valid_flags) 274 return TEE_ERROR_BAD_PARAMETERS; 275 276 if (!fops) { 277 res = TEE_ERROR_ITEM_NOT_FOUND; 278 goto exit; 279 } 280 281 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) { 282 res = TEE_ERROR_BAD_PARAMETERS; 283 goto exit; 284 } 285 286 res = tee_ta_get_current_session(&sess); 287 if (res != TEE_SUCCESS) 288 goto err; 289 utc = to_user_ta_ctx(sess->ctx); 290 291 res = tee_mmu_check_access_rights(&utc->uctx, 292 TEE_MEMORY_ACCESS_READ, 293 (uaddr_t) object_id, 294 object_id_len); 295 if (res != TEE_SUCCESS) 296 goto err; 297 298 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 299 object_id_len, flags, false, fops, &po); 300 if (res != TEE_SUCCESS) 301 goto err; 302 303 o = tee_obj_alloc(); 304 if (o == NULL) { 305 tee_pobj_release(po); 306 res = TEE_ERROR_OUT_OF_MEMORY; 307 goto err; 308 } 309 310 o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT | 311 TEE_HANDLE_FLAG_INITIALIZED | flags; 312 o->pobj = po; 313 tee_obj_add(utc, o); 314 315 res = tee_svc_storage_read_head(o); 316 if (res != TEE_SUCCESS) { 317 if (res == TEE_ERROR_CORRUPT_OBJECT) { 318 EMSG("Object corrupt"); 319 goto err; 320 } 321 goto oclose; 322 } 323 324 res = tee_svc_copy_kaddr_to_uref(obj, o); 325 if (res != TEE_SUCCESS) 326 goto oclose; 327 328 goto exit; 329 330 oclose: 331 tee_obj_close(utc, o); 332 o = NULL; 333 334 err: 335 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 336 res = TEE_ERROR_CORRUPT_OBJECT; 337 if (res == TEE_ERROR_CORRUPT_OBJECT && o) 338 tee_svc_storage_remove_corrupt_obj(sess, o); 339 340 exit: 341 free(file); 342 file = NULL; 343 return res; 344 } 345 346 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite, 347 struct tee_obj *attr_o, void *data, 348 uint32_t len) 349 { 350 TEE_Result res = TEE_SUCCESS; 351 struct tee_svc_storage_head head; 352 const struct tee_file_operations *fops = o->pobj->fops; 353 void *attr = NULL; 354 size_t attr_size = 0; 355 356 if (attr_o) { 357 res = tee_obj_set_type(o, attr_o->info.objectType, 358 attr_o->info.maxKeySize); 359 if (res) 360 return res; 361 res = tee_obj_attr_copy_from(o, attr_o); 362 if (res) 363 return res; 364 o->have_attrs = attr_o->have_attrs; 365 o->info.objectUsage = attr_o->info.objectUsage; 366 o->info.keySize = attr_o->info.keySize; 367 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 368 if (res) 369 return res; 370 if (attr_size) { 371 attr = malloc(attr_size); 372 if (!attr) 373 return TEE_ERROR_OUT_OF_MEMORY; 374 res = tee_obj_attr_to_binary(o, attr, &attr_size); 375 if (res != TEE_SUCCESS) 376 goto exit; 377 } 378 } else { 379 res = tee_obj_set_type(o, TEE_TYPE_DATA, 0); 380 if (res != TEE_SUCCESS) 381 goto exit; 382 } 383 384 o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size; 385 386 /* write head */ 387 head.attr_size = attr_size; 388 head.keySize = o->info.keySize; 389 head.maxKeySize = o->info.maxKeySize; 390 head.objectUsage = o->info.objectUsage; 391 head.objectType = o->info.objectType; 392 head.have_attrs = o->have_attrs; 393 394 res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr, 395 attr_size, data, len, &o->fh); 396 397 if (!res) 398 o->info.dataSize = len; 399 exit: 400 free(attr); 401 return res; 402 } 403 404 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id, 405 size_t object_id_len, unsigned long flags, 406 unsigned long attr, void *data, size_t len, 407 uint32_t *obj) 408 { 409 const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ | 410 TEE_DATA_FLAG_ACCESS_WRITE | 411 TEE_DATA_FLAG_ACCESS_WRITE_META | 412 TEE_DATA_FLAG_SHARE_READ | 413 TEE_DATA_FLAG_SHARE_WRITE | 414 TEE_DATA_FLAG_OVERWRITE; 415 const struct tee_file_operations *fops = 416 tee_svc_storage_file_ops(storage_id); 417 struct tee_ta_session *sess = NULL; 418 struct user_ta_ctx *utc = NULL; 419 struct tee_obj *attr_o = NULL; 420 TEE_Result res = TEE_SUCCESS; 421 struct tee_pobj *po = NULL; 422 struct tee_obj *o = NULL; 423 424 if (flags & ~valid_flags) 425 return TEE_ERROR_BAD_PARAMETERS; 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->uctx, TEE_MEMORY_ACCESS_READ, 439 (uaddr_t)object_id, object_id_len); 440 if (res != TEE_SUCCESS) 441 goto err; 442 443 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 444 object_id_len, flags, true, fops, &po); 445 if (res != TEE_SUCCESS) 446 goto err; 447 448 /* check rights of the provided buffer */ 449 if (len) { 450 if (data) { 451 uint32_t f = TEE_MEMORY_ACCESS_READ | 452 TEE_MEMORY_ACCESS_ANY_OWNER; 453 454 res = tee_mmu_check_access_rights(&utc->uctx, f, 455 (uaddr_t)data, len); 456 457 if (res != TEE_SUCCESS) 458 goto err; 459 } else { 460 res = TEE_ERROR_BAD_PARAMETERS; 461 goto err; 462 } 463 } 464 465 o = tee_obj_alloc(); 466 if (o == NULL) { 467 res = TEE_ERROR_OUT_OF_MEMORY; 468 goto err; 469 } 470 471 o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT | 472 TEE_HANDLE_FLAG_INITIALIZED | flags; 473 o->pobj = po; 474 475 if (attr != TEE_HANDLE_NULL) { 476 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr), 477 &attr_o); 478 if (res != TEE_SUCCESS) 479 goto err; 480 /* The supplied handle must be one of an initialized object */ 481 if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) { 482 res = TEE_ERROR_BAD_PARAMETERS; 483 goto err; 484 } 485 } 486 487 res = tee_svc_storage_init_file(o, flags & TEE_DATA_FLAG_OVERWRITE, 488 attr_o, data, len); 489 if (res != TEE_SUCCESS) 490 goto err; 491 492 po = NULL; /* o owns it from now on */ 493 tee_obj_add(utc, o); 494 495 res = tee_svc_copy_kaddr_to_uref(obj, o); 496 if (res != TEE_SUCCESS) 497 goto oclose; 498 499 return TEE_SUCCESS; 500 501 oclose: 502 tee_obj_close(utc, o); 503 return res; 504 505 err: 506 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 507 res = TEE_ERROR_CORRUPT_OBJECT; 508 if (res == TEE_ERROR_CORRUPT_OBJECT && po) 509 fops->remove(po); 510 if (o) { 511 fops->close(&o->fh); 512 tee_obj_free(o); 513 } 514 if (po) 515 tee_pobj_release(po); 516 517 return res; 518 } 519 520 TEE_Result syscall_storage_obj_del(unsigned long obj) 521 { 522 TEE_Result res; 523 struct tee_ta_session *sess; 524 struct tee_obj *o; 525 struct user_ta_ctx *utc; 526 527 res = tee_ta_get_current_session(&sess); 528 if (res != TEE_SUCCESS) 529 return res; 530 utc = to_user_ta_ctx(sess->ctx); 531 532 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 533 if (res != TEE_SUCCESS) 534 return res; 535 536 if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 537 return TEE_ERROR_ACCESS_CONFLICT; 538 539 if (o->pobj == NULL || o->pobj->obj_id == NULL) 540 return TEE_ERROR_BAD_STATE; 541 542 res = o->pobj->fops->remove(o->pobj); 543 tee_obj_close(utc, o); 544 545 return res; 546 } 547 548 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id, 549 size_t object_id_len) 550 { 551 const struct tee_file_operations *fops = NULL; 552 struct tee_ta_session *sess = NULL; 553 struct user_ta_ctx *utc = NULL; 554 TEE_Result res = TEE_SUCCESS; 555 struct tee_pobj *po = NULL; 556 struct tee_obj *o = NULL; 557 char *new_file = NULL; 558 char *old_file = NULL; 559 560 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 561 return TEE_ERROR_BAD_PARAMETERS; 562 563 res = tee_ta_get_current_session(&sess); 564 if (res != TEE_SUCCESS) 565 return res; 566 utc = to_user_ta_ctx(sess->ctx); 567 568 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 569 if (res != TEE_SUCCESS) 570 return res; 571 572 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 573 res = TEE_ERROR_BAD_STATE; 574 goto exit; 575 } 576 577 if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { 578 res = TEE_ERROR_BAD_STATE; 579 goto exit; 580 } 581 582 if (o->pobj == NULL || o->pobj->obj_id == NULL) { 583 res = TEE_ERROR_BAD_STATE; 584 goto exit; 585 } 586 587 res = tee_mmu_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ, 588 (uaddr_t)object_id, object_id_len); 589 if (res != TEE_SUCCESS) 590 goto exit; 591 592 /* reserve dest name */ 593 fops = o->pobj->fops; 594 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 595 object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, 596 false, fops, &po); 597 if (res != TEE_SUCCESS) 598 goto exit; 599 600 /* move */ 601 res = fops->rename(o->pobj, po, false /* no overwrite */); 602 if (res) 603 goto exit; 604 605 res = tee_pobj_rename(o->pobj, object_id, object_id_len); 606 607 exit: 608 tee_pobj_release(po); 609 610 free(new_file); 611 free(old_file); 612 613 return res; 614 } 615 616 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum) 617 { 618 struct tee_storage_enum *e; 619 struct tee_ta_session *sess; 620 TEE_Result res; 621 struct user_ta_ctx *utc; 622 623 if (obj_enum == NULL) 624 return TEE_ERROR_BAD_PARAMETERS; 625 626 res = tee_ta_get_current_session(&sess); 627 if (res != TEE_SUCCESS) 628 return res; 629 utc = to_user_ta_ctx(sess->ctx); 630 631 e = malloc(sizeof(struct tee_storage_enum)); 632 if (e == NULL) 633 return TEE_ERROR_OUT_OF_MEMORY; 634 635 e->dir = NULL; 636 e->fops = NULL; 637 TAILQ_INSERT_TAIL(&utc->storage_enums, e, link); 638 639 return tee_svc_copy_kaddr_to_uref(obj_enum, e); 640 } 641 642 TEE_Result syscall_storage_free_enum(unsigned long obj_enum) 643 { 644 struct tee_storage_enum *e; 645 TEE_Result res; 646 struct tee_ta_session *sess; 647 struct user_ta_ctx *utc; 648 649 res = tee_ta_get_current_session(&sess); 650 if (res != TEE_SUCCESS) 651 return res; 652 utc = to_user_ta_ctx(sess->ctx); 653 654 res = tee_svc_storage_get_enum(utc, 655 tee_svc_uref_to_vaddr(obj_enum), &e); 656 if (res != TEE_SUCCESS) 657 return res; 658 659 return tee_svc_close_enum(utc, e); 660 } 661 662 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum) 663 { 664 struct tee_storage_enum *e; 665 TEE_Result res; 666 struct tee_ta_session *sess; 667 668 res = tee_ta_get_current_session(&sess); 669 if (res != TEE_SUCCESS) 670 return res; 671 672 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 673 tee_svc_uref_to_vaddr(obj_enum), &e); 674 if (res != TEE_SUCCESS) 675 return res; 676 677 if (e->fops) { 678 e->fops->closedir(e->dir); 679 e->fops = NULL; 680 e->dir = NULL; 681 } 682 assert(!e->dir); 683 684 return TEE_SUCCESS; 685 } 686 687 static TEE_Result tee_svc_storage_set_enum(struct tee_fs_dirent *d, 688 const struct tee_file_operations *fops, 689 struct tee_obj *o) 690 { 691 o->info.handleFlags = 692 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 693 o->info.objectUsage = TEE_USAGE_DEFAULT; 694 695 if (d->oidlen > TEE_OBJECT_ID_MAX_LEN) 696 return TEE_ERROR_CORRUPT_OBJECT; 697 698 o->pobj->obj_id = malloc(d->oidlen); 699 if (!o->pobj->obj_id) 700 return TEE_ERROR_OUT_OF_MEMORY; 701 702 memcpy(o->pobj->obj_id, d->oid, d->oidlen); 703 o->pobj->obj_id_len = d->oidlen; 704 o->pobj->fops = fops; 705 706 return TEE_SUCCESS; 707 } 708 709 TEE_Result syscall_storage_start_enum(unsigned long obj_enum, 710 unsigned long storage_id) 711 { 712 struct tee_storage_enum *e; 713 TEE_Result res; 714 struct tee_ta_session *sess; 715 const struct tee_file_operations *fops = 716 tee_svc_storage_file_ops(storage_id); 717 718 res = tee_ta_get_current_session(&sess); 719 if (res != TEE_SUCCESS) 720 return res; 721 722 res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx), 723 tee_svc_uref_to_vaddr(obj_enum), &e); 724 if (res != TEE_SUCCESS) 725 return res; 726 727 if (e->dir) { 728 e->fops->closedir(e->dir); 729 e->dir = NULL; 730 } 731 732 if (!fops) 733 return TEE_ERROR_ITEM_NOT_FOUND; 734 735 e->fops = fops; 736 737 return fops->opendir(&sess->ctx->uuid, &e->dir); 738 } 739 740 TEE_Result syscall_storage_next_enum(unsigned long obj_enum, 741 TEE_ObjectInfo *info, void *obj_id, uint64_t *len) 742 { 743 struct tee_ta_session *sess = NULL; 744 struct tee_storage_enum *e = NULL; 745 struct tee_fs_dirent *d = NULL; 746 struct user_ta_ctx *utc = NULL; 747 TEE_Result res = TEE_SUCCESS; 748 struct tee_obj *o = NULL; 749 uint64_t l = 0; 750 751 res = tee_ta_get_current_session(&sess); 752 if (res != TEE_SUCCESS) 753 goto exit; 754 utc = to_user_ta_ctx(sess->ctx); 755 756 res = tee_svc_storage_get_enum(utc, 757 tee_svc_uref_to_vaddr(obj_enum), &e); 758 if (res != TEE_SUCCESS) 759 goto exit; 760 761 /* check rights of the provided buffers */ 762 res = tee_mmu_check_access_rights(&utc->uctx, 763 TEE_MEMORY_ACCESS_WRITE | 764 TEE_MEMORY_ACCESS_ANY_OWNER, 765 (uaddr_t)info, 766 sizeof(TEE_ObjectInfo)); 767 if (res != TEE_SUCCESS) 768 goto exit; 769 770 res = tee_mmu_check_access_rights(&utc->uctx, 771 TEE_MEMORY_ACCESS_WRITE | 772 TEE_MEMORY_ACCESS_ANY_OWNER, 773 (uaddr_t)obj_id, 774 TEE_OBJECT_ID_MAX_LEN); 775 if (res != TEE_SUCCESS) 776 goto exit; 777 778 if (!e->fops) { 779 res = TEE_ERROR_ITEM_NOT_FOUND; 780 goto exit; 781 } 782 783 res = e->fops->readdir(e->dir, &d); 784 if (res != TEE_SUCCESS) 785 goto exit; 786 787 o = tee_obj_alloc(); 788 if (o == NULL) { 789 res = TEE_ERROR_OUT_OF_MEMORY; 790 goto exit; 791 } 792 o->info.handleFlags = TEE_DATA_FLAG_SHARE_READ; 793 794 o->pobj = calloc(1, sizeof(struct tee_pobj)); 795 if (!o->pobj) { 796 res = TEE_ERROR_OUT_OF_MEMORY; 797 goto exit; 798 } 799 800 o->pobj->uuid = sess->ctx->uuid; 801 res = tee_svc_storage_set_enum(d, e->fops, o); 802 if (res != TEE_SUCCESS) 803 goto exit; 804 805 res = tee_svc_storage_read_head(o); 806 if (res != TEE_SUCCESS) 807 goto exit; 808 809 memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); 810 memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); 811 812 l = o->pobj->obj_id_len; 813 res = tee_svc_copy_to_user(len, &l, sizeof(*len)); 814 815 exit: 816 if (o) { 817 if (o->pobj) { 818 if (o->pobj->fops) 819 o->pobj->fops->close(&o->fh); 820 free(o->pobj->obj_id); 821 } 822 free(o->pobj); 823 tee_obj_free(o); 824 } 825 826 return res; 827 } 828 829 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len, 830 uint64_t *count) 831 { 832 struct tee_ta_session *sess = NULL; 833 struct user_ta_ctx *utc = NULL; 834 TEE_Result res = TEE_SUCCESS; 835 struct tee_obj *o = NULL; 836 uint64_t u_count = 0; 837 size_t pos_tmp = 0; 838 size_t bytes = 0; 839 840 res = tee_ta_get_current_session(&sess); 841 if (res != TEE_SUCCESS) 842 goto exit; 843 utc = to_user_ta_ctx(sess->ctx); 844 845 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 846 if (res != TEE_SUCCESS) 847 goto exit; 848 849 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 850 res = TEE_ERROR_BAD_STATE; 851 goto exit; 852 } 853 854 if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) { 855 res = TEE_ERROR_ACCESS_CONFLICT; 856 goto exit; 857 } 858 859 /* Guard o->info.dataPosition += bytes below from overflowing */ 860 if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) { 861 res = TEE_ERROR_OVERFLOW; 862 goto exit; 863 } 864 865 /* check rights of the provided buffer */ 866 res = tee_mmu_check_access_rights(&utc->uctx, 867 TEE_MEMORY_ACCESS_WRITE | 868 TEE_MEMORY_ACCESS_ANY_OWNER, 869 (uaddr_t)data, len); 870 if (res != TEE_SUCCESS) 871 goto exit; 872 873 bytes = len; 874 if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) { 875 res = TEE_ERROR_OVERFLOW; 876 goto exit; 877 } 878 res = o->pobj->fops->read(o->fh, pos_tmp, data, &bytes); 879 if (res != TEE_SUCCESS) { 880 if (res == TEE_ERROR_CORRUPT_OBJECT) { 881 EMSG("Object corrupt"); 882 tee_svc_storage_remove_corrupt_obj(sess, o); 883 } 884 goto exit; 885 } 886 887 o->info.dataPosition += bytes; 888 889 u_count = bytes; 890 res = tee_svc_copy_to_user(count, &u_count, sizeof(*count)); 891 exit: 892 return res; 893 } 894 895 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len) 896 { 897 struct tee_ta_session *sess = NULL; 898 struct user_ta_ctx *utc = NULL; 899 TEE_Result res = TEE_SUCCESS; 900 struct tee_obj *o = NULL; 901 size_t pos_tmp = 0; 902 903 res = tee_ta_get_current_session(&sess); 904 if (res != TEE_SUCCESS) 905 goto exit; 906 utc = to_user_ta_ctx(sess->ctx); 907 908 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o); 909 if (res != TEE_SUCCESS) 910 goto exit; 911 912 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 913 res = TEE_ERROR_BAD_STATE; 914 goto exit; 915 } 916 917 if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) { 918 res = TEE_ERROR_ACCESS_CONFLICT; 919 goto exit; 920 } 921 922 /* Guard o->info.dataPosition += bytes below from overflowing */ 923 if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) { 924 res = TEE_ERROR_OVERFLOW; 925 goto exit; 926 } 927 928 /* check rights of the provided buffer */ 929 res = tee_mmu_check_access_rights(&utc->uctx, 930 TEE_MEMORY_ACCESS_READ | 931 TEE_MEMORY_ACCESS_ANY_OWNER, 932 (uaddr_t)data, len); 933 if (res != TEE_SUCCESS) 934 goto exit; 935 936 if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) { 937 res = TEE_ERROR_ACCESS_CONFLICT; 938 goto exit; 939 } 940 res = o->pobj->fops->write(o->fh, pos_tmp, data, len); 941 if (res != TEE_SUCCESS) 942 goto exit; 943 944 o->info.dataPosition += len; 945 if (o->info.dataPosition > o->info.dataSize) 946 o->info.dataSize = o->info.dataPosition; 947 948 exit: 949 return res; 950 } 951 952 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len) 953 { 954 TEE_Result res; 955 struct tee_ta_session *sess; 956 struct tee_obj *o; 957 size_t off; 958 size_t attr_size; 959 960 res = tee_ta_get_current_session(&sess); 961 if (res != TEE_SUCCESS) 962 goto exit; 963 964 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 965 tee_svc_uref_to_vaddr(obj), &o); 966 if (res != TEE_SUCCESS) 967 goto exit; 968 969 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 970 res = TEE_ERROR_BAD_STATE; 971 goto exit; 972 } 973 974 if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) { 975 res = TEE_ERROR_ACCESS_CONFLICT; 976 goto exit; 977 } 978 979 res = tee_obj_attr_to_binary(o, NULL, &attr_size); 980 if (res != TEE_SUCCESS) 981 goto exit; 982 983 if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size, 984 &off)) { 985 res = TEE_ERROR_OVERFLOW; 986 goto exit; 987 } 988 if (ADD_OVERFLOW(len, off, &off)) { 989 res = TEE_ERROR_OVERFLOW; 990 goto exit; 991 } 992 res = o->pobj->fops->truncate(o->fh, off); 993 switch (res) { 994 case TEE_SUCCESS: 995 o->info.dataSize = len; 996 break; 997 case TEE_ERROR_CORRUPT_OBJECT: 998 EMSG("Object corruption"); 999 (void)tee_svc_storage_remove_corrupt_obj(sess, o); 1000 break; 1001 default: 1002 res = TEE_ERROR_GENERIC; 1003 break; 1004 } 1005 1006 exit: 1007 return res; 1008 } 1009 1010 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset, 1011 unsigned long whence) 1012 { 1013 TEE_Result res; 1014 struct tee_ta_session *sess; 1015 struct tee_obj *o; 1016 tee_fs_off_t new_pos; 1017 1018 res = tee_ta_get_current_session(&sess); 1019 if (res != TEE_SUCCESS) 1020 return res; 1021 1022 res = tee_obj_get(to_user_ta_ctx(sess->ctx), 1023 tee_svc_uref_to_vaddr(obj), &o); 1024 if (res != TEE_SUCCESS) 1025 return res; 1026 1027 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) 1028 return TEE_ERROR_BAD_STATE; 1029 1030 switch (whence) { 1031 case TEE_DATA_SEEK_SET: 1032 new_pos = offset; 1033 break; 1034 case TEE_DATA_SEEK_CUR: 1035 if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos)) 1036 return TEE_ERROR_OVERFLOW; 1037 break; 1038 case TEE_DATA_SEEK_END: 1039 if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos)) 1040 return TEE_ERROR_OVERFLOW; 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