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 <tee/tee_svc_storage.h> 29 30 #include <kernel/tee_ta_manager.h> 31 #include <tee_api_defines.h> 32 #include <kernel/tee_misc.h> 33 #include <tee/tee_fs.h> 34 #include <tee/tee_fs_defs.h> 35 #include <tee/tee_obj.h> 36 #include <tee/tee_svc.h> 37 #include <mm/tee_mmu.h> 38 #include <tee/tee_pobj.h> 39 #include <trace.h> 40 41 /* SSF (Secure Storage File version 00 */ 42 #define TEE_SVC_STORAGE_MAGIC 0x53534600; 43 44 /* Header of GP formated secure storage files */ 45 struct tee_svc_storage_head { 46 uint32_t magic; 47 uint32_t head_size; 48 uint32_t meta_size; 49 uint32_t ds_size; 50 }; 51 52 struct tee_storage_enum { 53 TAILQ_ENTRY(tee_storage_enum) link; 54 tee_fs_dir *dir; 55 }; 56 57 static TEE_Result tee_svc_storage_get_enum(struct tee_ta_ctx *ctx, 58 uint32_t enum_id, 59 struct tee_storage_enum **e_out) 60 { 61 struct tee_storage_enum *e; 62 63 TAILQ_FOREACH(e, &ctx->storage_enums, link) { 64 if (enum_id == (vaddr_t)e) { 65 *e_out = e; 66 return TEE_SUCCESS; 67 } 68 } 69 return TEE_ERROR_BAD_PARAMETERS; 70 } 71 72 static TEE_Result tee_svc_close_enum(struct tee_ta_ctx *ctx, 73 struct tee_storage_enum *e) 74 { 75 int ret; 76 77 if (e == NULL || ctx == NULL) 78 return TEE_ERROR_BAD_PARAMETERS; 79 80 TAILQ_REMOVE(&ctx->storage_enums, e, link); 81 82 ret = tee_file_ops.closedir(e->dir); 83 e->dir = NULL; 84 85 free(e); 86 87 if (ret != 0) 88 return TEE_ERROR_ITEM_NOT_FOUND; 89 90 return TEE_SUCCESS; 91 } 92 93 static char *tee_svc_storage_create_filename(struct tee_ta_session *sess, 94 void *object_id, 95 uint32_t object_id_len, 96 bool transient) 97 { 98 uint8_t *file = NULL; 99 /* +1 for the '/' (default) */ 100 uint32_t hslen = 101 TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len) + 1; 102 uint32_t pos; 103 104 /* +1 for the '.' (temporary persistent object) */ 105 if (transient) 106 hslen++; 107 108 file = malloc(hslen); 109 110 if (file == NULL) 111 return NULL; 112 113 pos = tee_b2hs((uint8_t *)&sess->ctx->head->uuid, file, 114 sizeof(TEE_UUID), hslen); 115 file[pos] = '/'; 116 pos++; 117 118 /* temporary persistent object : uuid/.object_id_len_of(object_id) */ 119 if (transient) { 120 file[pos] = '.'; 121 pos++; 122 } 123 124 tee_b2hs(object_id, file + pos, object_id_len, hslen - pos); 125 126 return (char *)file; 127 } 128 129 static char *tee_svc_storage_create_dirname(struct tee_ta_session *sess) 130 { 131 uint8_t *dir = NULL; 132 uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)); 133 134 dir = malloc(hslen); 135 136 if (dir == NULL) 137 return NULL; 138 139 tee_b2hs((uint8_t *)&sess->ctx->head->uuid, dir, sizeof(TEE_UUID), 140 hslen); 141 142 return (char *)dir; 143 } 144 145 static uint32_t tee_svc_storage_conv_oflags(uint32_t flags) 146 { 147 uint32_t out = 0; 148 149 if (flags & (TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_SHARE_READ)) { 150 if (flags & (TEE_DATA_FLAG_ACCESS_WRITE | 151 TEE_DATA_FLAG_ACCESS_WRITE_META | 152 TEE_DATA_FLAG_SHARE_WRITE)) 153 out |= TEE_FS_O_RDWR; 154 else 155 out |= TEE_FS_O_RDONLY; 156 } else { 157 if (flags & (TEE_DATA_FLAG_ACCESS_WRITE | 158 TEE_DATA_FLAG_ACCESS_WRITE_META | 159 TEE_DATA_FLAG_SHARE_WRITE)) 160 out |= TEE_FS_O_WRONLY; 161 } 162 163 return out; 164 } 165 166 static int tee_svc_storage_conv_whence(TEE_Whence whence) 167 { 168 switch (whence) { 169 case TEE_DATA_SEEK_SET: 170 return TEE_FS_SEEK_SET; 171 case TEE_DATA_SEEK_CUR: 172 return TEE_FS_SEEK_CUR; 173 case TEE_DATA_SEEK_END: 174 return TEE_FS_SEEK_END; 175 default: 176 return -1; 177 } 178 } 179 180 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess, 181 char *file, int *fd) 182 { 183 TEE_Result res = TEE_SUCCESS; 184 char *dir = NULL; 185 int tmp; 186 uint32_t cflags = TEE_FS_O_WRONLY | TEE_FS_O_CREATE; 187 188 *fd = tee_file_ops.open(file, cflags); 189 190 if (*fd < 0) { 191 /* try and make directory */ 192 dir = tee_svc_storage_create_dirname(sess); 193 if (dir == NULL) { 194 res = TEE_ERROR_OUT_OF_MEMORY; 195 goto exit; 196 } 197 198 tmp = tee_file_ops.mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR); 199 free(dir); 200 201 if (tmp < 0) { 202 /* error codes needs better granularity */ 203 res = TEE_ERROR_GENERIC; 204 goto exit; 205 } 206 207 /* try and open again */ 208 *fd = tee_file_ops.open(file, cflags); 209 210 if (*fd < 0) { 211 /* error codes needs better granularity */ 212 res = TEE_ERROR_GENERIC; 213 goto exit; 214 } 215 } 216 217 exit: 218 219 return res; 220 } 221 222 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess, 223 struct tee_obj *o) 224 { 225 TEE_Result res = TEE_SUCCESS; 226 int fd = -1; 227 int err; 228 struct tee_svc_storage_head head; 229 char *file = NULL; 230 231 if (o == NULL || o->pobj == NULL) 232 return TEE_ERROR_BAD_PARAMETERS; 233 234 file = tee_svc_storage_create_filename(sess, 235 o->pobj->obj_id, 236 o->pobj->obj_id_len, 237 false); 238 if (file == NULL) { 239 res = TEE_ERROR_OUT_OF_MEMORY; 240 goto exit; 241 } 242 243 fd = tee_file_ops.open(file, TEE_FS_O_RDONLY); 244 free(file); 245 246 /* error codes needs better granularity */ 247 if (fd < 0) 248 return TEE_ERROR_ITEM_NOT_FOUND; 249 250 /* read head */ 251 err = tee_file_ops.read(fd, &head, sizeof(struct tee_svc_storage_head)); 252 if (err != sizeof(struct tee_svc_storage_head)) { 253 res = TEE_ERROR_BAD_FORMAT; 254 goto exit; 255 } 256 257 o->data_size = head.meta_size; 258 o->info.dataSize = head.ds_size; 259 260 o->data = malloc(o->data_size); 261 if (o->data == NULL) { 262 res = TEE_ERROR_OUT_OF_MEMORY; 263 goto exit; 264 } 265 266 /* read meta */ 267 err = tee_file_ops.read(fd, o->data, o->data_size); 268 if (err != (int)o->data_size) { 269 free(o->data); 270 o->data = NULL; 271 res = TEE_ERROR_NO_DATA; 272 } 273 274 exit: 275 tee_file_ops.close(fd); 276 277 return res; 278 } 279 280 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess, 281 struct tee_obj *o, 282 struct tee_obj *attr_o, void *data, 283 uint32_t len) 284 { 285 TEE_Result res = TEE_SUCCESS; 286 int fd = -1; 287 int err = -1; 288 struct tee_svc_storage_head head; 289 char *tmpfile = NULL; 290 291 if (o == NULL || o->pobj == NULL) 292 return TEE_ERROR_BAD_PARAMETERS; 293 294 free(o->data); 295 296 /* create temporary persistent object filename */ 297 tmpfile = tee_svc_storage_create_filename(sess, 298 o->pobj->obj_id, 299 o->pobj->obj_id_len, 300 true); 301 302 if (tmpfile == NULL) { 303 res = TEE_ERROR_OUT_OF_MEMORY; 304 goto exit; 305 } 306 307 res = tee_svc_storage_create_file(sess, tmpfile, &fd); 308 if (res != TEE_SUCCESS) 309 goto exit; 310 311 if (attr_o && attr_o->data_size) { 312 o->data_size = attr_o->data_size; 313 o->data = malloc(attr_o->data_size); 314 if (o->data == NULL) { 315 res = TEE_ERROR_OUT_OF_MEMORY; 316 goto exit; 317 } 318 319 memcpy(o->data, attr_o->data, attr_o->data_size); 320 o->have_attrs = attr_o->have_attrs; 321 o->info.objectUsage = attr_o->info.objectUsage; 322 o->info.objectType = attr_o->info.objectType; 323 } else { 324 o->data = NULL; 325 o->data_size = 0; 326 o->have_attrs = 0; 327 o->info.objectUsage = TEE_USAGE_DEFAULT; 328 o->info.objectType = TEE_TYPE_DATA; 329 } 330 331 /* write head */ 332 head.magic = TEE_SVC_STORAGE_MAGIC; 333 head.head_size = sizeof(struct tee_svc_storage_head); 334 head.meta_size = o->data_size; 335 head.ds_size = len; 336 337 /* write head */ 338 err = tee_file_ops.write(fd, &head, 339 sizeof(struct tee_svc_storage_head)); 340 /* error codes needs better granularity */ 341 if (err != sizeof(struct tee_svc_storage_head)) { 342 res = TEE_ERROR_GENERIC; 343 goto exit; 344 } 345 346 /* write meta */ 347 err = tee_file_ops.write(fd, o->data, o->data_size); 348 /* error codes needs better granularity */ 349 if (err != (int)o->data_size) { 350 res = TEE_ERROR_GENERIC; 351 goto exit; 352 } 353 354 /* write init data */ 355 o->info.dataSize = len; 356 357 /* write data to fs if needed */ 358 if (data && len) { 359 err = tee_file_ops.write(fd, data, len); 360 361 if (err != (int)len) { 362 /* error codes needs better granularity */ 363 res = TEE_ERROR_GENERIC; 364 goto exit; 365 } 366 } 367 368 exit: 369 free(tmpfile); 370 tmpfile = NULL; 371 if (fd != -1) 372 tee_file_ops.close(fd); 373 374 return res; 375 } 376 377 static TEE_Result tee_svc_storage_remove(struct tee_ta_session *sess, 378 uint32_t storage_id, void *object_id, 379 uint32_t object_id_len) 380 { 381 TEE_Result res = TEE_SUCCESS; 382 char *file = NULL; 383 int err; 384 385 if (sess == NULL) 386 return TEE_ERROR_BAD_PARAMETERS; 387 388 if (storage_id != TEE_STORAGE_PRIVATE) 389 return TEE_ERROR_ITEM_NOT_FOUND; 390 391 file = tee_svc_storage_create_filename(sess, object_id, 392 object_id_len, false); 393 if (file == NULL) 394 return TEE_ERROR_OUT_OF_MEMORY; 395 396 err = tee_file_ops.unlink(file); 397 free(file); 398 if (err != 0) 399 /* error codes needs better granularity */ 400 res = TEE_ERROR_GENERIC; 401 402 return res; 403 } 404 405 TEE_Result tee_svc_storage_obj_open(uint32_t storage_id, void *object_id, 406 uint32_t object_id_len, uint32_t flags, 407 uint32_t *obj) 408 { 409 TEE_Result res; 410 struct tee_ta_session *sess; 411 struct tee_obj *o; 412 char *file = NULL; 413 int fs_flags; 414 int fd = -1; 415 tee_fs_off_t off; 416 tee_fs_off_t e_off; 417 struct tee_pobj *po = NULL; 418 419 if (storage_id != TEE_STORAGE_PRIVATE) 420 return TEE_ERROR_ITEM_NOT_FOUND; 421 422 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 423 return TEE_ERROR_BAD_PARAMETERS; 424 425 res = tee_ta_get_current_session(&sess); 426 if (res != TEE_SUCCESS) 427 goto exit; 428 429 res = 430 tee_mmu_check_access_rights(sess->ctx, 431 TEE_MEMORY_ACCESS_READ | 432 TEE_MEMORY_ACCESS_ANY_OWNER, 433 (tee_uaddr_t) object_id, object_id_len); 434 if (res != TEE_SUCCESS) 435 goto exit; 436 437 res = tee_pobj_get((void *)&sess->ctx->head->uuid, object_id, 438 object_id_len, flags, &po); 439 if (res != TEE_SUCCESS) 440 goto exit; 441 442 fs_flags = tee_svc_storage_conv_oflags(flags); 443 444 o = calloc(1, sizeof(*o)); 445 if (o == NULL) { 446 res = TEE_ERROR_OUT_OF_MEMORY; 447 goto exit; 448 } 449 450 o->info.handleFlags = 451 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 452 o->info.objectUsage = TEE_USAGE_DEFAULT; 453 o->flags = flags; 454 o->pobj = po; 455 456 res = tee_svc_storage_read_head(sess, o); 457 if (res != TEE_SUCCESS) { 458 free(o); 459 goto exit; 460 } 461 462 file = tee_svc_storage_create_filename(sess, object_id, 463 object_id_len, false); 464 if (file == NULL) { 465 res = TEE_ERROR_OUT_OF_MEMORY; 466 goto exit; 467 } 468 469 fd = tee_file_ops.open(file, fs_flags); 470 free(file); 471 if (fd < 0) { 472 res = TEE_ERROR_ITEM_NOT_FOUND; 473 goto exit; 474 } 475 o->fd = fd; 476 477 tee_obj_add(sess->ctx, o); 478 479 res = tee_svc_copy_kaddr_to_user32(sess, obj, o); 480 if (res != TEE_SUCCESS) 481 tee_obj_close(sess->ctx, o); 482 483 e_off = sizeof(struct tee_svc_storage_head) + o->data_size; 484 off = tee_file_ops.lseek(fd, e_off, TEE_FS_SEEK_SET); 485 if (off != e_off) { 486 res = TEE_ERROR_NO_DATA; 487 goto exit; 488 } 489 490 exit: 491 if (res != TEE_SUCCESS) { 492 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) { 493 /* the file is corrupt, delete */ 494 tee_svc_storage_remove(sess, storage_id, object_id, 495 object_id_len); 496 497 /* "greaceful" return */ 498 res = TEE_ERROR_ITEM_NOT_FOUND; 499 } 500 501 if (fd >= 0) 502 tee_file_ops.close(fd); 503 if (po) 504 tee_pobj_release(po); 505 } 506 507 return res; 508 } 509 510 TEE_Result tee_svc_storage_obj_create(uint32_t storage_id, void *object_id, 511 uint32_t object_id_len, uint32_t flags, 512 uint32_t attr, void *data, uint32_t len, 513 uint32_t *obj) 514 { 515 TEE_Result res; 516 struct tee_ta_session *sess; 517 struct tee_obj *o = NULL; 518 struct tee_obj *attr_o = NULL; 519 char *file = NULL; 520 int fd = -1; 521 int fs_flags; 522 tee_fs_off_t off; 523 tee_fs_off_t e_off; 524 struct tee_pobj *po = NULL; 525 char *tmpfile = NULL; 526 int err = -1; 527 528 if (storage_id != TEE_STORAGE_PRIVATE) 529 return TEE_ERROR_ITEM_NOT_FOUND; 530 531 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 532 return TEE_ERROR_BAD_PARAMETERS; 533 534 res = tee_ta_get_current_session(&sess); 535 if (res != TEE_SUCCESS) 536 return res; 537 538 res = tee_mmu_check_access_rights(sess->ctx, 539 TEE_MEMORY_ACCESS_READ | 540 TEE_MEMORY_ACCESS_ANY_OWNER, 541 (tee_uaddr_t) object_id, 542 object_id_len); 543 if (res != TEE_SUCCESS) 544 goto err; 545 546 res = tee_pobj_get((void *)&sess->ctx->head->uuid, object_id, 547 object_id_len, flags, &po); 548 if (res != TEE_SUCCESS) 549 goto err; 550 551 /* check rights of the provided buffer */ 552 if (data && len) { 553 res = tee_mmu_check_access_rights(sess->ctx, 554 TEE_MEMORY_ACCESS_READ | 555 TEE_MEMORY_ACCESS_ANY_OWNER, 556 (tee_uaddr_t) data, len); 557 558 if (res != TEE_SUCCESS) 559 goto err; 560 } 561 562 o = calloc(1, sizeof(*o)); 563 if (o == NULL) { 564 res = TEE_ERROR_OUT_OF_MEMORY; 565 goto err; 566 } 567 568 o->info.handleFlags = 569 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 570 o->flags = flags; 571 o->pobj = po; 572 573 if (attr != TEE_HANDLE_NULL) { 574 /* init attributes if provided */ 575 res = tee_obj_get(sess->ctx, attr, &attr_o); 576 if (res != TEE_SUCCESS) 577 goto err; 578 } 579 580 res = tee_svc_storage_init_file(sess, o, attr_o, data, len); 581 if (res != TEE_SUCCESS) 582 goto err; 583 584 /* create persistent object filename */ 585 file = tee_svc_storage_create_filename(sess, object_id, 586 object_id_len, false); 587 if (file == NULL) { 588 res = TEE_ERROR_OUT_OF_MEMORY; 589 goto err; 590 } 591 592 err = tee_file_ops.access(file, TEE_FS_F_OK); 593 if (!err) { 594 /* file exists */ 595 if (!(flags & TEE_DATA_FLAG_OVERWRITE)) { 596 res = TEE_ERROR_ACCESS_CONFLICT; 597 goto rmfile; 598 } 599 } 600 601 /* create temporary persistent object filename */ 602 tmpfile = tee_svc_storage_create_filename(sess, object_id, 603 object_id_len, 604 true); 605 if (tmpfile == NULL) { 606 res = TEE_ERROR_OUT_OF_MEMORY; 607 goto err; 608 } 609 610 /* rename temporary persistent object filename */ 611 err = tee_file_ops.rename(tmpfile, file); 612 if (err) { 613 /* error codes needs better granularity */ 614 res = TEE_ERROR_GENERIC; 615 goto rmfile; 616 } 617 618 fs_flags = tee_svc_storage_conv_oflags(flags); 619 620 fd = tee_file_ops.open(file, fs_flags); 621 if (fd < 0) { 622 res = TEE_ERROR_ITEM_NOT_FOUND; 623 goto err; 624 } 625 o->fd = fd; 626 627 tee_obj_add(sess->ctx, o); 628 629 res = tee_svc_copy_kaddr_to_user32(sess, obj, o); 630 if (res != TEE_SUCCESS) 631 goto oclose; 632 633 e_off = sizeof(struct tee_svc_storage_head) + o->data_size; 634 off = tee_file_ops.lseek(fd, e_off, TEE_FS_SEEK_SET); 635 if (off != e_off) { 636 res = TEE_ERROR_NO_DATA; 637 goto oclose; 638 } 639 640 goto exit; 641 642 oclose: 643 tee_obj_close(sess->ctx, o); 644 goto exit; 645 646 rmfile: 647 tee_file_ops.unlink(tmpfile); 648 649 err: 650 if (fd >= 0) 651 tee_file_ops.close(fd); 652 if (po) 653 tee_pobj_release(po); 654 if (o) 655 free(o); 656 657 exit: 658 free(file); 659 file = NULL; 660 free(tmpfile); 661 tmpfile = NULL; 662 663 return res; 664 } 665 666 TEE_Result tee_svc_storage_obj_del(uint32_t obj) 667 { 668 TEE_Result res; 669 struct tee_ta_session *sess; 670 struct tee_obj *o; 671 int err; 672 char *file; 673 char *dir; 674 675 res = tee_ta_get_current_session(&sess); 676 if (res != TEE_SUCCESS) 677 return res; 678 679 res = tee_obj_get(sess->ctx, obj, &o); 680 if (res != TEE_SUCCESS) 681 return res; 682 683 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 684 return TEE_ERROR_ACCESS_CONFLICT; 685 686 if (o->pobj == NULL || o->pobj->obj_id == NULL) 687 return TEE_ERROR_BAD_STATE; 688 689 file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 690 o->pobj->obj_id_len, false); 691 if (file == NULL) 692 return TEE_ERROR_OUT_OF_MEMORY; 693 694 tee_obj_close(sess->ctx, o); 695 696 /* TODO add TEE_ERROR_STORAGE_NOT_AVAILABLE implementation */ 697 698 err = tee_file_ops.unlink(file); 699 free(file); 700 if (err != 0) 701 /* error codes needs better granularity */ 702 return TEE_ERROR_GENERIC; 703 704 /* try and remove dir */ 705 dir = tee_svc_storage_create_dirname(sess); 706 if (dir == NULL) 707 return TEE_ERROR_OUT_OF_MEMORY; 708 /* ignore result */ 709 tee_file_ops.rmdir(dir); 710 free(dir); 711 712 return TEE_SUCCESS; 713 } 714 715 TEE_Result tee_svc_storage_obj_rename(uint32_t obj, void *object_id, 716 uint32_t object_id_len) 717 { 718 TEE_Result res; 719 struct tee_ta_session *sess; 720 struct tee_obj *o; 721 struct tee_pobj *po = NULL; 722 char *new_file = NULL; 723 char *old_file = NULL; 724 int err = -1; 725 726 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 727 return TEE_ERROR_BAD_PARAMETERS; 728 729 res = tee_ta_get_current_session(&sess); 730 if (res != TEE_SUCCESS) 731 return res; 732 733 res = tee_obj_get(sess->ctx, obj, &o); 734 if (res != TEE_SUCCESS) 735 return res; 736 737 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { 738 res = TEE_ERROR_BAD_STATE; 739 goto exit; 740 } 741 742 if (o->pobj == NULL || o->pobj->obj_id == NULL) 743 return TEE_ERROR_BAD_STATE; 744 745 res = 746 tee_mmu_check_access_rights(sess->ctx, 747 TEE_MEMORY_ACCESS_READ | 748 TEE_MEMORY_ACCESS_ANY_OWNER, 749 (tee_uaddr_t) object_id, object_id_len); 750 if (res != TEE_SUCCESS) 751 goto exit; 752 753 /* get new ds name */ 754 new_file = tee_svc_storage_create_filename(sess, object_id, 755 object_id_len, false); 756 if (new_file == NULL) { 757 res = TEE_ERROR_OUT_OF_MEMORY; 758 goto exit; 759 } 760 761 old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 762 o->pobj->obj_id_len, false); 763 if (old_file == NULL) { 764 res = TEE_ERROR_OUT_OF_MEMORY; 765 goto exit; 766 } 767 768 /* reserve dest name */ 769 res = tee_pobj_get((void *)&sess->ctx->head->uuid, object_id, 770 object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, &po); 771 if (res != TEE_SUCCESS) 772 goto exit; 773 774 err = tee_file_ops.access(new_file, TEE_FS_F_OK); 775 if (err == 0) { 776 /* file exists */ 777 res = TEE_ERROR_ACCESS_CONFLICT; 778 goto exit; 779 } 780 781 /* move */ 782 err = tee_file_ops.rename(old_file, new_file); 783 if (err) { 784 /* error codes needs better granularity */ 785 res = TEE_ERROR_GENERIC; 786 goto exit; 787 } 788 789 res = tee_pobj_rename(o->pobj, object_id, object_id_len); 790 791 exit: 792 tee_pobj_release(po); 793 794 free(new_file); 795 free(old_file); 796 797 return res; 798 } 799 800 TEE_Result tee_svc_storage_alloc_enum(uint32_t *obj_enum) 801 { 802 struct tee_storage_enum *e; 803 struct tee_ta_session *sess; 804 TEE_Result res; 805 806 if (obj_enum == NULL) 807 return TEE_ERROR_BAD_PARAMETERS; 808 809 res = tee_ta_get_current_session(&sess); 810 if (res != TEE_SUCCESS) 811 return res; 812 813 e = malloc(sizeof(struct tee_storage_enum)); 814 815 if (e == NULL) 816 return TEE_ERROR_OUT_OF_MEMORY; 817 818 e->dir = NULL; 819 TAILQ_INSERT_TAIL(&sess->ctx->storage_enums, e, link); 820 821 return tee_svc_copy_kaddr_to_user32(sess, obj_enum, e); 822 } 823 824 TEE_Result tee_svc_storage_free_enum(uint32_t obj_enum) 825 { 826 struct tee_storage_enum *e; 827 TEE_Result res; 828 struct tee_ta_session *sess; 829 830 if (obj_enum == TEE_HANDLE_NULL) 831 return TEE_SUCCESS; 832 833 res = tee_ta_get_current_session(&sess); 834 if (res != TEE_SUCCESS) 835 return res; 836 837 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 838 if (res != TEE_SUCCESS) 839 return res; 840 841 return tee_svc_close_enum(sess->ctx, e); 842 } 843 844 TEE_Result tee_svc_storage_reset_enum(uint32_t obj_enum) 845 { 846 struct tee_storage_enum *e; 847 int res; 848 struct tee_ta_session *sess; 849 850 res = tee_ta_get_current_session(&sess); 851 if (res != TEE_SUCCESS) 852 return res; 853 854 if (obj_enum == TEE_HANDLE_NULL) 855 return TEE_SUCCESS; 856 857 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 858 if (res != TEE_SUCCESS) 859 return res; 860 861 res = tee_file_ops.closedir(e->dir); 862 e->dir = NULL; 863 if (res != 0) 864 return TEE_ERROR_GENERIC; 865 866 return TEE_SUCCESS; 867 } 868 869 TEE_Result tee_svc_storage_start_enum(uint32_t obj_enum, uint32_t storage_id) 870 { 871 struct tee_storage_enum *e; 872 char *dir; 873 TEE_Result res; 874 struct tee_ta_session *sess; 875 876 if (obj_enum == TEE_HANDLE_NULL) 877 return TEE_ERROR_BAD_PARAMETERS; 878 879 res = tee_ta_get_current_session(&sess); 880 if (res != TEE_SUCCESS) 881 return res; 882 883 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 884 if (res != TEE_SUCCESS) 885 return res; 886 887 if (storage_id != TEE_STORAGE_PRIVATE) 888 return TEE_ERROR_ITEM_NOT_FOUND; 889 890 dir = tee_svc_storage_create_dirname(sess); 891 if (dir == NULL) 892 return TEE_ERROR_OUT_OF_MEMORY; 893 894 e->dir = tee_file_ops.opendir(dir); 895 free(dir); 896 897 if (e->dir == NULL) 898 /* error codes needs better granularity */ 899 return TEE_ERROR_ITEM_NOT_FOUND; 900 901 return TEE_SUCCESS; 902 } 903 904 TEE_Result tee_svc_storage_next_enum(uint32_t obj_enum, TEE_ObjectInfo *info, 905 void *obj_id, uint32_t *len) 906 { 907 struct tee_storage_enum *e; 908 struct tee_fs_dirent *d; 909 TEE_Result res = TEE_SUCCESS; 910 struct tee_ta_session *sess; 911 struct tee_obj *o = NULL; 912 uint32_t blen; 913 uint32_t hslen; 914 915 res = tee_ta_get_current_session(&sess); 916 if (res != TEE_SUCCESS) 917 return res; 918 919 if (obj_enum == TEE_HANDLE_NULL) 920 return TEE_ERROR_BAD_PARAMETERS; 921 922 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 923 if (res != TEE_SUCCESS) 924 return res; 925 926 /* check rights of the provided buffers */ 927 res = 928 tee_mmu_check_access_rights(sess->ctx, 929 TEE_MEMORY_ACCESS_WRITE | 930 TEE_MEMORY_ACCESS_ANY_OWNER, 931 (tee_uaddr_t) info, 932 sizeof(TEE_ObjectInfo)); 933 if (res != TEE_SUCCESS) 934 return res; 935 936 res = 937 tee_mmu_check_access_rights(sess->ctx, 938 TEE_MEMORY_ACCESS_WRITE | 939 TEE_MEMORY_ACCESS_ANY_OWNER, 940 (tee_uaddr_t) obj_id, 941 TEE_OBJECT_ID_MAX_LEN); 942 if (res != TEE_SUCCESS) 943 return res; 944 945 d = tee_file_ops.readdir(e->dir); 946 if (d == NULL) 947 return TEE_ERROR_ITEM_NOT_FOUND; 948 949 o = calloc(1, sizeof(struct tee_obj)); 950 if (o == NULL) { 951 res = TEE_ERROR_OUT_OF_MEMORY; 952 goto exit; 953 } 954 955 o->pobj = calloc(1, sizeof(struct tee_pobj)); 956 if (!o->pobj) { 957 res = TEE_ERROR_OUT_OF_MEMORY; 958 goto exit; 959 } 960 961 o->info.handleFlags = 962 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 963 o->info.objectUsage = TEE_USAGE_DEFAULT; 964 965 /* 966 * NOTE: Special usage of pobj due to not ref cnt should be inc 967 */ 968 hslen = strlen(d->d_name); 969 blen = TEE_HS2B_BBUF_SIZE(hslen); 970 o->pobj->obj_id = malloc(blen); 971 if (o->pobj->obj_id == NULL) { 972 res = TEE_ERROR_OUT_OF_MEMORY; 973 goto exit; 974 } 975 tee_hs2b((uint8_t *)d->d_name, o->pobj->obj_id, hslen, blen); 976 o->pobj->obj_id_len = blen; 977 978 res = tee_svc_storage_read_head(sess, o); 979 if (res != TEE_SUCCESS) { 980 /* TODO: handle corrupt files in a greaceful way */ 981 goto exit; 982 } 983 memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); 984 memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); 985 986 res = 987 tee_svc_copy_to_user(sess, len, &o->pobj->obj_id_len, 988 sizeof(uint32_t)); 989 990 exit: 991 if (o) { 992 if (o->pobj) 993 free(o->pobj->obj_id); 994 free(o->pobj); 995 free(o->data); 996 } 997 free(o); 998 999 return res; 1000 } 1001 1002 TEE_Result tee_svc_storage_obj_read(uint32_t obj, void *data, size_t len, 1003 uint32_t *count) 1004 { 1005 TEE_Result res; 1006 struct tee_ta_session *sess; 1007 struct tee_obj *o; 1008 int n_count; 1009 uint32_t u_count; 1010 1011 res = tee_ta_get_current_session(&sess); 1012 if (res != TEE_SUCCESS) 1013 return res; 1014 1015 res = tee_obj_get(sess->ctx, obj, &o); 1016 if (res != TEE_SUCCESS) 1017 return res; 1018 1019 if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) 1020 return TEE_ERROR_ACCESS_CONFLICT; 1021 1022 /* check rights of the provided buffer */ 1023 res = 1024 tee_mmu_check_access_rights(sess->ctx, 1025 TEE_MEMORY_ACCESS_WRITE | 1026 TEE_MEMORY_ACCESS_ANY_OWNER, 1027 (tee_uaddr_t) data, len); 1028 if (res != TEE_SUCCESS) 1029 return res; 1030 1031 n_count = tee_file_ops.read(o->fd, data, len); 1032 u_count = (uint32_t) ((n_count < 0) ? 0 : n_count); 1033 1034 res = tee_svc_copy_to_user(sess, count, &u_count, sizeof(uint32_t)); 1035 1036 o->info.dataPosition += u_count; 1037 1038 return TEE_SUCCESS; 1039 } 1040 1041 TEE_Result tee_svc_storage_obj_write(uint32_t obj, void *data, size_t len) 1042 { 1043 TEE_Result res; 1044 struct tee_ta_session *sess; 1045 struct tee_obj *o; 1046 int err; 1047 1048 res = tee_ta_get_current_session(&sess); 1049 if (res != TEE_SUCCESS) 1050 return res; 1051 1052 res = tee_obj_get(sess->ctx, obj, &o); 1053 if (res != TEE_SUCCESS) 1054 return res; 1055 1056 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) 1057 return TEE_ERROR_ACCESS_CONFLICT; 1058 1059 /* check rights of the provided buffer */ 1060 res = 1061 tee_mmu_check_access_rights(sess->ctx, 1062 TEE_MEMORY_ACCESS_READ | 1063 TEE_MEMORY_ACCESS_ANY_OWNER, 1064 (tee_uaddr_t) data, len); 1065 1066 err = tee_file_ops.write(o->fd, data, len); 1067 1068 if (err != (int)len) { 1069 /* error codes needs better granularity */ 1070 res = TEE_ERROR_GENERIC; 1071 return res; 1072 } 1073 1074 o->info.dataPosition += len; 1075 if (o->info.dataPosition > o->info.dataSize) 1076 o->info.dataSize = o->info.dataPosition; 1077 1078 return TEE_SUCCESS; 1079 } 1080 1081 TEE_Result tee_svc_storage_obj_trunc(uint32_t obj, size_t len) 1082 { 1083 TEE_Result res; 1084 struct tee_ta_session *sess; 1085 struct tee_obj *o; 1086 int err; 1087 tee_fs_off_t off; 1088 1089 res = tee_ta_get_current_session(&sess); 1090 if (res != TEE_SUCCESS) 1091 return res; 1092 1093 res = tee_obj_get(sess->ctx, obj, &o); 1094 if (res != TEE_SUCCESS) 1095 return res; 1096 1097 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) 1098 return TEE_ERROR_ACCESS_CONFLICT; 1099 1100 off = sizeof(struct tee_svc_storage_head) + o->data_size; 1101 err = tee_file_ops.ftruncate(o->fd, len + off); 1102 1103 if (err != 0) 1104 /* error codes needs better granularity */ 1105 return TEE_ERROR_GENERIC; 1106 1107 return TEE_SUCCESS; 1108 } 1109 1110 TEE_Result tee_svc_storage_obj_seek(uint32_t obj, int32_t offset, 1111 TEE_Whence whence) 1112 { 1113 TEE_Result res; 1114 struct tee_ta_session *sess; 1115 struct tee_obj *o; 1116 int fw; 1117 tee_fs_off_t off; 1118 tee_fs_off_t e_off = 0; 1119 1120 res = tee_ta_get_current_session(&sess); 1121 if (res != TEE_SUCCESS) 1122 return res; 1123 1124 res = tee_obj_get(sess->ctx, obj, &o); 1125 if (res != TEE_SUCCESS) 1126 return res; 1127 1128 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) 1129 return TEE_ERROR_BAD_STATE; 1130 1131 fw = tee_svc_storage_conv_whence(whence); 1132 1133 if (whence == TEE_DATA_SEEK_SET) 1134 e_off = sizeof(struct tee_svc_storage_head) + o->data_size; 1135 1136 off = tee_file_ops.lseek(o->fd, e_off + offset, fw); 1137 if (off > -1 && off >= e_off) 1138 o->info.dataPosition = off - 1139 (sizeof(struct tee_svc_storage_head) + o->data_size); 1140 else 1141 return TEE_ERROR_GENERIC; 1142 1143 return TEE_SUCCESS; 1144 } 1145 1146 void tee_svc_storage_close_all_enum(struct tee_ta_ctx *ctx) 1147 { 1148 struct tee_storage_enum_head *eh = &ctx->storage_enums; 1149 1150 /* disregard return value */ 1151 while (!TAILQ_EMPTY(eh)) 1152 tee_svc_close_enum(ctx, TAILQ_FIRST(eh)); 1153 } 1154