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