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