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 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->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 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->uuid, dir, sizeof(TEE_UUID), 140 hslen); 141 142 return (char *)dir; 143 } 144 145 static TEE_Result tee_svc_storage_remove_corrupt_obj( 146 struct tee_ta_session *sess, 147 struct tee_obj *o) 148 { 149 TEE_Result res; 150 char *file = NULL; 151 char *dir = NULL; 152 153 file = tee_svc_storage_create_filename(sess, 154 o->pobj->obj_id, 155 o->pobj->obj_id_len, 156 false); 157 if (file == NULL) { 158 res = TEE_ERROR_OUT_OF_MEMORY; 159 goto exit; 160 } 161 162 tee_obj_close(sess->ctx, o); 163 tee_file_ops.unlink(file); 164 free(file); 165 dir = tee_svc_storage_create_dirname(sess); 166 if (dir != NULL) { 167 tee_file_ops.rmdir(dir); 168 free(dir); 169 } 170 171 res = TEE_SUCCESS; 172 173 exit: 174 return res; 175 } 176 177 static uint32_t tee_svc_storage_conv_oflags(uint32_t flags) 178 { 179 uint32_t out = 0; 180 181 if (flags & (TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_SHARE_READ)) { 182 if (flags & (TEE_DATA_FLAG_ACCESS_WRITE | 183 TEE_DATA_FLAG_ACCESS_WRITE_META | 184 TEE_DATA_FLAG_SHARE_WRITE)) 185 out |= TEE_FS_O_RDWR; 186 else 187 out |= TEE_FS_O_RDONLY; 188 } else { 189 if (flags & (TEE_DATA_FLAG_ACCESS_WRITE | 190 TEE_DATA_FLAG_ACCESS_WRITE_META | 191 TEE_DATA_FLAG_SHARE_WRITE)) 192 out |= TEE_FS_O_WRONLY; 193 } 194 195 return out; 196 } 197 198 static int tee_svc_storage_conv_whence(TEE_Whence whence) 199 { 200 switch (whence) { 201 case TEE_DATA_SEEK_SET: 202 return TEE_FS_SEEK_SET; 203 case TEE_DATA_SEEK_CUR: 204 return TEE_FS_SEEK_CUR; 205 case TEE_DATA_SEEK_END: 206 return TEE_FS_SEEK_END; 207 default: 208 return -1; 209 } 210 } 211 212 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess, 213 char *file, int *fd) 214 { 215 TEE_Result res = TEE_SUCCESS; 216 char *dir = NULL; 217 int tmp; 218 int err; 219 uint32_t cflags = TEE_FS_O_WRONLY | 220 TEE_FS_O_CREATE | TEE_FS_O_TRUNC; 221 222 dir = tee_svc_storage_create_dirname(sess); 223 if (dir == NULL) { 224 res = TEE_ERROR_OUT_OF_MEMORY; 225 goto exit; 226 } 227 228 /* try and make directory */ 229 err = tee_file_ops.access(dir, TEE_FS_F_OK); 230 if (err) { 231 /* directory does not exists */ 232 tmp = tee_file_ops.mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR); 233 234 if (tmp < 0) { 235 /* error codes needs better granularity */ 236 res = TEE_ERROR_GENERIC; 237 goto exit; 238 } 239 } 240 241 /* try and open again */ 242 *fd = tee_file_ops.open(&res, file, cflags); 243 244 exit: 245 free(dir); 246 247 return res; 248 } 249 250 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess, 251 struct tee_obj *o) 252 { 253 TEE_Result res = TEE_SUCCESS; 254 int fd = -1; 255 int err; 256 struct tee_svc_storage_head head; 257 char *file = NULL; 258 259 if (o == NULL || o->pobj == NULL) 260 return TEE_ERROR_BAD_PARAMETERS; 261 262 file = tee_svc_storage_create_filename(sess, 263 o->pobj->obj_id, 264 o->pobj->obj_id_len, 265 false); 266 if (file == NULL) { 267 res = TEE_ERROR_OUT_OF_MEMORY; 268 goto exit; 269 } 270 271 fd = tee_file_ops.open(&res, file, TEE_FS_O_RDONLY); 272 free(file); 273 if (fd < 0) 274 goto exit; 275 276 /* read head */ 277 err = tee_file_ops.read(&res, fd, &head, 278 sizeof(struct tee_svc_storage_head)); 279 if (err < 0) { 280 if (res == TEE_ERROR_CORRUPT_OBJECT) 281 EMSG("Head corrupt\n"); 282 goto exit; 283 } 284 285 if (err != sizeof(struct tee_svc_storage_head)) { 286 res = TEE_ERROR_BAD_FORMAT; 287 goto exit; 288 } 289 290 o->data_size = head.meta_size; 291 o->info.dataSize = head.ds_size; 292 293 o->data = malloc(o->data_size); 294 if (o->data == NULL) { 295 res = TEE_ERROR_OUT_OF_MEMORY; 296 goto exit; 297 } 298 299 /* read meta */ 300 err = tee_file_ops.read(&res, fd, o->data, o->data_size); 301 if (err != (int)o->data_size) { 302 free(o->data); 303 o->data = NULL; 304 } 305 306 exit: 307 if (fd >= 0) 308 tee_file_ops.close(fd); 309 310 return res; 311 } 312 313 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess, 314 struct tee_obj *o, 315 struct tee_obj *attr_o, void *data, 316 uint32_t len) 317 { 318 TEE_Result res = TEE_SUCCESS; 319 int fd = -1; 320 int err = -1; 321 struct tee_svc_storage_head head; 322 char *tmpfile = NULL; 323 324 if (o == NULL || o->pobj == NULL) 325 return TEE_ERROR_BAD_PARAMETERS; 326 327 free(o->data); 328 329 /* create temporary persistent object filename */ 330 tmpfile = tee_svc_storage_create_filename(sess, 331 o->pobj->obj_id, 332 o->pobj->obj_id_len, 333 true); 334 335 if (tmpfile == NULL) { 336 res = TEE_ERROR_OUT_OF_MEMORY; 337 goto exit; 338 } 339 340 res = tee_svc_storage_create_file(sess, tmpfile, &fd); 341 if (res != TEE_SUCCESS) 342 goto exit; 343 344 if (attr_o && attr_o->data_size) { 345 o->data_size = attr_o->data_size; 346 o->data = malloc(attr_o->data_size); 347 if (o->data == NULL) { 348 res = TEE_ERROR_OUT_OF_MEMORY; 349 goto exit; 350 } 351 352 memcpy(o->data, attr_o->data, attr_o->data_size); 353 o->have_attrs = attr_o->have_attrs; 354 o->info.objectUsage = attr_o->info.objectUsage; 355 o->info.objectType = attr_o->info.objectType; 356 } else { 357 o->data = NULL; 358 o->data_size = 0; 359 o->have_attrs = 0; 360 o->info.objectUsage = TEE_USAGE_DEFAULT; 361 o->info.objectType = TEE_TYPE_DATA; 362 } 363 364 /* write head */ 365 head.magic = TEE_SVC_STORAGE_MAGIC; 366 head.head_size = sizeof(struct tee_svc_storage_head); 367 head.meta_size = o->data_size; 368 head.ds_size = len; 369 370 /* write head */ 371 err = tee_file_ops.write(&res, fd, &head, 372 sizeof(struct tee_svc_storage_head)); 373 /* error codes needs better granularity */ 374 if (err != sizeof(struct tee_svc_storage_head)) 375 goto exit; 376 377 /* write meta */ 378 err = tee_file_ops.write(&res, fd, o->data, o->data_size); 379 if (err != (int)o->data_size) 380 goto exit; 381 382 /* write init data */ 383 o->info.dataSize = len; 384 385 /* write data to fs if needed */ 386 if (data && len) { 387 err = tee_file_ops.write(&res, fd, data, len); 388 if (err != (int)len) 389 goto exit; 390 } 391 392 exit: 393 free(tmpfile); 394 tmpfile = NULL; 395 if (fd != -1) 396 tee_file_ops.close(fd); 397 398 return res; 399 } 400 401 TEE_Result syscall_storage_obj_open(uint32_t storage_id, void *object_id, 402 uint32_t object_id_len, uint32_t flags, 403 uint32_t *obj) 404 { 405 TEE_Result res; 406 struct tee_ta_session *sess; 407 struct tee_obj *o; 408 char *file = NULL; 409 int fs_flags; 410 int fd = -1; 411 tee_fs_off_t off; 412 tee_fs_off_t e_off; 413 struct tee_pobj *po = NULL; 414 int err = -1; 415 416 if (storage_id != TEE_STORAGE_PRIVATE) { 417 res = TEE_ERROR_ITEM_NOT_FOUND; 418 goto exit; 419 } 420 421 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) { 422 res = TEE_ERROR_BAD_PARAMETERS; 423 goto exit; 424 } 425 426 res = tee_ta_get_current_session(&sess); 427 if (res != TEE_SUCCESS) 428 goto err; 429 430 res = tee_mmu_check_access_rights(sess->ctx, 431 TEE_MEMORY_ACCESS_READ | 432 TEE_MEMORY_ACCESS_ANY_OWNER, 433 (tee_uaddr_t) object_id, 434 object_id_len); 435 if (res != TEE_SUCCESS) 436 goto err; 437 438 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 439 object_id_len, flags, &po); 440 if (res != TEE_SUCCESS) 441 goto err; 442 443 fs_flags = tee_svc_storage_conv_oflags(flags); 444 445 o = calloc(1, sizeof(*o)); 446 if (o == NULL) { 447 res = TEE_ERROR_OUT_OF_MEMORY; 448 goto err; 449 } 450 451 o->info.handleFlags = 452 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 453 o->info.objectUsage = TEE_USAGE_DEFAULT; 454 o->flags = flags; 455 o->pobj = po; 456 457 res = tee_svc_storage_read_head(sess, o); 458 if (res != TEE_SUCCESS) { 459 tee_obj_add(sess->ctx, o); 460 if (res == TEE_ERROR_CORRUPT_OBJECT) { 461 EMSG("Object corrupt\n"); 462 res = tee_svc_storage_remove_corrupt_obj(sess, o); 463 if (res != TEE_SUCCESS) 464 goto exit; 465 res = TEE_ERROR_CORRUPT_OBJECT; 466 goto exit; 467 } 468 goto oclose; 469 } 470 471 file = tee_svc_storage_create_filename(sess, object_id, 472 object_id_len, false); 473 if (file == NULL) { 474 res = TEE_ERROR_OUT_OF_MEMORY; 475 goto err; 476 } 477 478 err = tee_file_ops.access(file, TEE_FS_F_OK); 479 if (err) { 480 /* file not found */ 481 res = TEE_ERROR_STORAGE_NOT_AVAILABLE; 482 goto err; 483 } 484 485 fd = tee_file_ops.open(&res, file, fs_flags); 486 if (fd < 0) { 487 goto err; 488 } 489 o->fd = fd; 490 491 tee_obj_add(sess->ctx, o); 492 493 res = tee_svc_copy_kaddr_to_user32(sess, obj, o); 494 if (res != TEE_SUCCESS) 495 goto oclose; 496 497 e_off = sizeof(struct tee_svc_storage_head) + o->data_size; 498 off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET); 499 if (off != e_off) { 500 res = TEE_ERROR_NO_DATA; 501 goto oclose; 502 } 503 504 goto exit; 505 506 oclose: 507 tee_obj_close(sess->ctx, o); 508 509 err: 510 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 511 res = TEE_ERROR_CORRUPT_OBJECT; 512 if (res == TEE_ERROR_CORRUPT_OBJECT) 513 tee_file_ops.unlink(file); 514 if (fd >= 0) 515 tee_file_ops.close(fd); 516 if (po) 517 tee_pobj_release(po); 518 519 exit: 520 free(file); 521 file = NULL; 522 return res; 523 } 524 525 TEE_Result syscall_storage_obj_create(uint32_t storage_id, void *object_id, 526 uint32_t object_id_len, uint32_t flags, 527 uint32_t attr, void *data, uint32_t len, 528 uint32_t *obj) 529 { 530 TEE_Result res; 531 struct tee_ta_session *sess; 532 struct tee_obj *o = NULL; 533 struct tee_obj *attr_o = NULL; 534 char *file = NULL; 535 int fd = -1; 536 int fs_flags; 537 tee_fs_off_t off; 538 tee_fs_off_t e_off; 539 struct tee_pobj *po = NULL; 540 char *tmpfile = NULL; 541 int err = -1; 542 543 if (storage_id != TEE_STORAGE_PRIVATE) 544 return TEE_ERROR_ITEM_NOT_FOUND; 545 546 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 547 return TEE_ERROR_BAD_PARAMETERS; 548 549 res = tee_ta_get_current_session(&sess); 550 if (res != TEE_SUCCESS) 551 return res; 552 553 res = tee_mmu_check_access_rights(sess->ctx, 554 TEE_MEMORY_ACCESS_READ | 555 TEE_MEMORY_ACCESS_ANY_OWNER, 556 (tee_uaddr_t) object_id, 557 object_id_len); 558 if (res != TEE_SUCCESS) 559 goto err; 560 561 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 562 object_id_len, flags, &po); 563 if (res != TEE_SUCCESS) 564 goto err; 565 566 /* check rights of the provided buffer */ 567 if (data && len) { 568 res = tee_mmu_check_access_rights(sess->ctx, 569 TEE_MEMORY_ACCESS_READ | 570 TEE_MEMORY_ACCESS_ANY_OWNER, 571 (tee_uaddr_t) data, len); 572 573 if (res != TEE_SUCCESS) 574 goto err; 575 } 576 577 o = calloc(1, sizeof(*o)); 578 if (o == NULL) { 579 res = TEE_ERROR_OUT_OF_MEMORY; 580 goto err; 581 } 582 583 o->info.handleFlags = 584 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 585 o->flags = flags; 586 o->pobj = po; 587 588 if (attr != TEE_HANDLE_NULL) { 589 /* init attributes if provided */ 590 res = tee_obj_get(sess->ctx, attr, &attr_o); 591 if (res != TEE_SUCCESS) 592 goto err; 593 } 594 595 res = tee_svc_storage_init_file(sess, o, attr_o, data, len); 596 if (res != TEE_SUCCESS) 597 goto err; 598 599 /* create persistent object filename */ 600 file = tee_svc_storage_create_filename(sess, object_id, 601 object_id_len, false); 602 if (file == NULL) { 603 res = TEE_ERROR_OUT_OF_MEMORY; 604 goto err; 605 } 606 607 err = tee_file_ops.access(file, TEE_FS_F_OK); 608 if (!err) { 609 /* file exists */ 610 if (!(flags & TEE_DATA_FLAG_OVERWRITE)) { 611 res = TEE_ERROR_ACCESS_CONFLICT; 612 goto err; 613 } 614 } 615 616 /* create temporary persistent object filename */ 617 tmpfile = tee_svc_storage_create_filename(sess, object_id, 618 object_id_len, 619 true); 620 if (tmpfile == NULL) { 621 res = TEE_ERROR_OUT_OF_MEMORY; 622 goto err; 623 } 624 625 /* rename temporary persistent object filename */ 626 err = tee_file_ops.rename(tmpfile, file); 627 if (err) { 628 /* error codes needs better granularity */ 629 res = TEE_ERROR_GENERIC; 630 goto rmfile; 631 } 632 633 fs_flags = tee_svc_storage_conv_oflags(flags); 634 635 fd = tee_file_ops.open(&res, file, fs_flags); 636 if (fd < 0) { 637 goto err; 638 } 639 o->fd = fd; 640 641 tee_obj_add(sess->ctx, o); 642 643 res = tee_svc_copy_kaddr_to_user32(sess, obj, o); 644 if (res != TEE_SUCCESS) 645 goto oclose; 646 647 e_off = sizeof(struct tee_svc_storage_head) + o->data_size; 648 off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET); 649 if (off != e_off) { 650 res = TEE_ERROR_NO_DATA; 651 goto oclose; 652 } 653 654 goto exit; 655 656 oclose: 657 tee_obj_close(sess->ctx, o); 658 goto exit; 659 660 rmfile: 661 tee_file_ops.unlink(tmpfile); 662 663 err: 664 if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) 665 res = TEE_ERROR_CORRUPT_OBJECT; 666 if (res == TEE_ERROR_CORRUPT_OBJECT) 667 tee_file_ops.unlink(file); 668 if (fd >= 0) 669 tee_file_ops.close(fd); 670 if (po) 671 tee_pobj_release(po); 672 if (o) 673 free(o); 674 675 exit: 676 free(file); 677 file = NULL; 678 free(tmpfile); 679 tmpfile = NULL; 680 681 return res; 682 } 683 684 TEE_Result syscall_storage_obj_del(uint32_t obj) 685 { 686 TEE_Result res; 687 struct tee_ta_session *sess; 688 struct tee_obj *o; 689 int err; 690 char *file; 691 char *dir; 692 693 res = tee_ta_get_current_session(&sess); 694 if (res != TEE_SUCCESS) 695 return res; 696 697 res = tee_obj_get(sess->ctx, obj, &o); 698 if (res != TEE_SUCCESS) 699 return res; 700 701 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 702 return TEE_ERROR_ACCESS_CONFLICT; 703 704 if (o->pobj == NULL || o->pobj->obj_id == NULL) 705 return TEE_ERROR_BAD_STATE; 706 707 file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 708 o->pobj->obj_id_len, false); 709 if (file == NULL) 710 return TEE_ERROR_OUT_OF_MEMORY; 711 712 tee_obj_close(sess->ctx, o); 713 714 err = tee_file_ops.access(file, TEE_FS_F_OK); 715 if (err) 716 /* file not found */ 717 return TEE_ERROR_STORAGE_NOT_AVAILABLE; 718 719 err = tee_file_ops.unlink(file); 720 free(file); 721 if (err) 722 /* error codes needs better granularity */ 723 return TEE_ERROR_GENERIC; 724 725 /* try and remove dir */ 726 dir = tee_svc_storage_create_dirname(sess); 727 if (dir == NULL) 728 return TEE_ERROR_OUT_OF_MEMORY; 729 /* ignore result */ 730 tee_file_ops.rmdir(dir); 731 free(dir); 732 733 return TEE_SUCCESS; 734 } 735 736 TEE_Result syscall_storage_obj_rename(uint32_t obj, void *object_id, 737 uint32_t object_id_len) 738 { 739 TEE_Result res; 740 struct tee_ta_session *sess; 741 struct tee_obj *o; 742 struct tee_pobj *po = NULL; 743 char *new_file = NULL; 744 char *old_file = NULL; 745 int err = -1; 746 747 if (object_id_len > TEE_OBJECT_ID_MAX_LEN) 748 return TEE_ERROR_BAD_PARAMETERS; 749 750 res = tee_ta_get_current_session(&sess); 751 if (res != TEE_SUCCESS) 752 return res; 753 754 res = tee_obj_get(sess->ctx, obj, &o); 755 if (res != TEE_SUCCESS) 756 return res; 757 758 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 759 res = TEE_ERROR_BAD_STATE; 760 goto exit; 761 } 762 763 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { 764 res = TEE_ERROR_BAD_STATE; 765 goto exit; 766 } 767 768 if (o->pobj == NULL || o->pobj->obj_id == NULL) { 769 res = TEE_ERROR_BAD_STATE; 770 goto exit; 771 } 772 773 res = tee_mmu_check_access_rights(sess->ctx, 774 TEE_MEMORY_ACCESS_READ | 775 TEE_MEMORY_ACCESS_ANY_OWNER, 776 (tee_uaddr_t) object_id, object_id_len); 777 if (res != TEE_SUCCESS) 778 goto exit; 779 780 res = tee_obj_verify(sess, o); 781 if (res != TEE_SUCCESS) 782 goto exit; 783 784 /* get new ds name */ 785 new_file = tee_svc_storage_create_filename(sess, object_id, 786 object_id_len, false); 787 if (new_file == NULL) { 788 res = TEE_ERROR_OUT_OF_MEMORY; 789 goto exit; 790 } 791 792 old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id, 793 o->pobj->obj_id_len, false); 794 if (old_file == NULL) { 795 res = TEE_ERROR_OUT_OF_MEMORY; 796 goto exit; 797 } 798 799 /* reserve dest name */ 800 res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, 801 object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, &po); 802 if (res != TEE_SUCCESS) 803 goto exit; 804 805 err = tee_file_ops.access(new_file, TEE_FS_F_OK); 806 if (err == 0) { 807 /* file exists */ 808 res = TEE_ERROR_ACCESS_CONFLICT; 809 goto exit; 810 } 811 812 /* move */ 813 err = tee_file_ops.rename(old_file, new_file); 814 if (err) { 815 /* error codes needs better granularity */ 816 res = TEE_ERROR_GENERIC; 817 goto exit; 818 } 819 820 res = tee_pobj_rename(o->pobj, object_id, object_id_len); 821 822 exit: 823 tee_pobj_release(po); 824 825 free(new_file); 826 free(old_file); 827 828 return res; 829 } 830 831 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum) 832 { 833 struct tee_storage_enum *e; 834 struct tee_ta_session *sess; 835 TEE_Result res; 836 837 if (obj_enum == NULL) 838 return TEE_ERROR_BAD_PARAMETERS; 839 840 res = tee_ta_get_current_session(&sess); 841 if (res != TEE_SUCCESS) 842 return res; 843 844 e = malloc(sizeof(struct tee_storage_enum)); 845 846 if (e == NULL) 847 return TEE_ERROR_OUT_OF_MEMORY; 848 849 e->dir = NULL; 850 TAILQ_INSERT_TAIL(&sess->ctx->storage_enums, e, link); 851 852 return tee_svc_copy_kaddr_to_user32(sess, obj_enum, e); 853 } 854 855 TEE_Result syscall_storage_free_enum(uint32_t obj_enum) 856 { 857 struct tee_storage_enum *e; 858 TEE_Result res; 859 struct tee_ta_session *sess; 860 861 if (obj_enum == TEE_HANDLE_NULL) 862 return TEE_SUCCESS; 863 864 res = tee_ta_get_current_session(&sess); 865 if (res != TEE_SUCCESS) 866 return res; 867 868 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 869 if (res != TEE_SUCCESS) 870 return res; 871 872 return tee_svc_close_enum(sess->ctx, e); 873 } 874 875 TEE_Result syscall_storage_reset_enum(uint32_t obj_enum) 876 { 877 struct tee_storage_enum *e; 878 int res; 879 struct tee_ta_session *sess; 880 881 res = tee_ta_get_current_session(&sess); 882 if (res != TEE_SUCCESS) 883 return res; 884 885 if (obj_enum == TEE_HANDLE_NULL) 886 return TEE_SUCCESS; 887 888 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 889 if (res != TEE_SUCCESS) 890 return res; 891 892 res = tee_file_ops.closedir(e->dir); 893 e->dir = NULL; 894 if (res != 0) 895 return TEE_ERROR_GENERIC; 896 897 return TEE_SUCCESS; 898 } 899 900 static TEE_Result tee_svc_storage_set_enum(char *d_name, struct tee_obj *o) 901 { 902 TEE_Result res; 903 uint32_t blen; 904 uint32_t hslen; 905 906 o->info.handleFlags = 907 TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; 908 o->info.objectUsage = TEE_USAGE_DEFAULT; 909 910 hslen = strlen(d_name); 911 blen = TEE_HS2B_BBUF_SIZE(hslen); 912 o->pobj->obj_id = malloc(blen); 913 if (!o->pobj->obj_id) { 914 res = TEE_ERROR_OUT_OF_MEMORY; 915 goto exit; 916 } 917 tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen); 918 o->pobj->obj_id_len = blen; 919 920 res = TEE_SUCCESS; 921 922 exit: 923 return res; 924 925 } 926 927 TEE_Result syscall_storage_start_enum(uint32_t obj_enum, uint32_t storage_id) 928 { 929 struct tee_storage_enum *e; 930 char *dir; 931 TEE_Result res; 932 struct tee_ta_session *sess; 933 struct tee_fs_dirent *d = NULL; 934 struct tee_obj *o = NULL; 935 936 if (obj_enum == TEE_HANDLE_NULL) 937 return TEE_ERROR_BAD_PARAMETERS; 938 939 res = tee_ta_get_current_session(&sess); 940 if (res != TEE_SUCCESS) 941 return res; 942 943 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 944 if (res != TEE_SUCCESS) 945 return res; 946 947 if (storage_id != TEE_STORAGE_PRIVATE) 948 return TEE_ERROR_ITEM_NOT_FOUND; 949 950 dir = tee_svc_storage_create_dirname(sess); 951 if (dir == NULL) 952 return TEE_ERROR_OUT_OF_MEMORY; 953 954 e->dir = tee_file_ops.opendir(dir); 955 free(dir); 956 957 if (e->dir == NULL) 958 /* error codes needs better granularity */ 959 return TEE_ERROR_ITEM_NOT_FOUND; 960 961 /* verify object */ 962 o = calloc(1, sizeof(struct tee_obj)); 963 if (o == NULL) { 964 res = TEE_ERROR_OUT_OF_MEMORY; 965 goto exit; 966 } 967 968 o->pobj = calloc(1, sizeof(struct tee_pobj)); 969 if (!o->pobj) { 970 res = TEE_ERROR_OUT_OF_MEMORY; 971 goto exit; 972 } 973 974 /* object enumeration loop */ 975 do { 976 d = tee_file_ops.readdir(e->dir); 977 if (d) { 978 /* allocate obj_id and set object */ 979 res = tee_svc_storage_set_enum(d->d_name, o); 980 if (res != TEE_SUCCESS) 981 goto exit; 982 res = tee_obj_verify(sess, o); 983 if (res != TEE_SUCCESS) 984 goto exit; 985 /* free obj_id for each iteration */ 986 free(o->pobj->obj_id); 987 /* force obj_id to skip freeing at exit statement */ 988 o->pobj->obj_id = NULL; 989 } 990 } while (d); 991 992 /* re-start */ 993 res = tee_file_ops.closedir(e->dir); 994 e->dir = NULL; 995 if (res != 0) { 996 res = TEE_ERROR_GENERIC; 997 goto exit; 998 } 999 1000 dir = tee_svc_storage_create_dirname(sess); 1001 if (dir == NULL) { 1002 res = TEE_ERROR_OUT_OF_MEMORY; 1003 goto exit; 1004 } 1005 1006 e->dir = tee_file_ops.opendir(dir); 1007 free(dir); 1008 1009 exit: 1010 if (o) { 1011 if (o->pobj) 1012 free(o->pobj->obj_id); 1013 free(o->pobj); 1014 free(o->data); 1015 } 1016 free(o); 1017 1018 return res; 1019 } 1020 1021 TEE_Result syscall_storage_next_enum(uint32_t obj_enum, TEE_ObjectInfo *info, 1022 void *obj_id, uint32_t *len) 1023 { 1024 struct tee_storage_enum *e; 1025 struct tee_fs_dirent *d; 1026 TEE_Result res = TEE_SUCCESS; 1027 struct tee_ta_session *sess; 1028 struct tee_obj *o = NULL; 1029 1030 if (obj_enum == TEE_HANDLE_NULL) { 1031 res = TEE_ERROR_BAD_PARAMETERS; 1032 goto exit; 1033 } 1034 1035 res = tee_ta_get_current_session(&sess); 1036 if (res != TEE_SUCCESS) 1037 goto exit; 1038 1039 res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); 1040 if (res != TEE_SUCCESS) 1041 goto exit; 1042 1043 /* check rights of the provided buffers */ 1044 res = tee_mmu_check_access_rights(sess->ctx, 1045 TEE_MEMORY_ACCESS_WRITE | 1046 TEE_MEMORY_ACCESS_ANY_OWNER, 1047 (tee_uaddr_t) info, 1048 sizeof(TEE_ObjectInfo)); 1049 if (res != TEE_SUCCESS) 1050 goto exit; 1051 1052 res = tee_mmu_check_access_rights(sess->ctx, 1053 TEE_MEMORY_ACCESS_WRITE | 1054 TEE_MEMORY_ACCESS_ANY_OWNER, 1055 (tee_uaddr_t) obj_id, 1056 TEE_OBJECT_ID_MAX_LEN); 1057 if (res != TEE_SUCCESS) 1058 goto exit; 1059 1060 d = tee_file_ops.readdir(e->dir); 1061 if (d == NULL) { 1062 res = TEE_ERROR_ITEM_NOT_FOUND; 1063 goto exit; 1064 } 1065 1066 o = calloc(1, sizeof(struct tee_obj)); 1067 if (o == NULL) { 1068 res = TEE_ERROR_OUT_OF_MEMORY; 1069 goto exit; 1070 } 1071 1072 o->pobj = calloc(1, sizeof(struct tee_pobj)); 1073 if (!o->pobj) { 1074 res = TEE_ERROR_OUT_OF_MEMORY; 1075 goto exit; 1076 } 1077 1078 res = tee_svc_storage_set_enum(d->d_name, o); 1079 if (res != TEE_SUCCESS) 1080 goto exit; 1081 1082 res = tee_obj_verify(sess, o); 1083 if (res != TEE_SUCCESS) 1084 goto exit; 1085 1086 res = tee_svc_storage_read_head(sess, o); 1087 if (res != TEE_SUCCESS) 1088 goto exit; 1089 1090 memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); 1091 memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); 1092 1093 res = tee_svc_copy_to_user(sess, len, &o->pobj->obj_id_len, 1094 sizeof(uint32_t)); 1095 1096 exit: 1097 if (o) { 1098 if (o->pobj) 1099 free(o->pobj->obj_id); 1100 free(o->pobj); 1101 free(o->data); 1102 } 1103 free(o); 1104 1105 return res; 1106 } 1107 1108 TEE_Result syscall_storage_obj_read(uint32_t obj, void *data, size_t len, 1109 uint32_t *count) 1110 { 1111 TEE_Result res; 1112 struct tee_ta_session *sess; 1113 struct tee_obj *o; 1114 int n_count; 1115 uint32_t u_count; 1116 1117 res = tee_ta_get_current_session(&sess); 1118 if (res != TEE_SUCCESS) 1119 goto exit; 1120 1121 res = tee_obj_get(sess->ctx, obj, &o); 1122 if (res != TEE_SUCCESS) 1123 goto exit; 1124 1125 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1126 res = TEE_ERROR_BAD_STATE; 1127 goto exit; 1128 } 1129 1130 if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) { 1131 res = TEE_ERROR_ACCESS_CONFLICT; 1132 goto exit; 1133 } 1134 1135 /* check rights of the provided buffer */ 1136 res = tee_mmu_check_access_rights(sess->ctx, 1137 TEE_MEMORY_ACCESS_WRITE | 1138 TEE_MEMORY_ACCESS_ANY_OWNER, 1139 (tee_uaddr_t) data, len); 1140 if (res != TEE_SUCCESS) 1141 goto exit; 1142 1143 n_count = tee_file_ops.read(&res, o->fd, data, len); 1144 if (n_count < 0) { 1145 EMSG("Error code=%x\n", (uint32_t)res); 1146 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1147 EMSG("Object corrupt\n"); 1148 tee_svc_storage_remove_corrupt_obj(sess, o); 1149 } 1150 goto exit; 1151 } 1152 u_count = (uint32_t) ((n_count < 0) ? 0 : n_count); 1153 1154 res = tee_svc_copy_to_user(sess, count, &u_count, sizeof(uint32_t)); 1155 1156 o->info.dataPosition += u_count; 1157 1158 res = TEE_SUCCESS; 1159 1160 exit: 1161 return res; 1162 } 1163 1164 TEE_Result syscall_storage_obj_write(uint32_t obj, void *data, size_t len) 1165 { 1166 TEE_Result res; 1167 struct tee_ta_session *sess; 1168 struct tee_obj *o; 1169 int err; 1170 1171 res = tee_ta_get_current_session(&sess); 1172 if (res != TEE_SUCCESS) 1173 goto exit; 1174 1175 res = tee_obj_get(sess->ctx, obj, &o); 1176 if (res != TEE_SUCCESS) 1177 goto exit; 1178 1179 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1180 res = TEE_ERROR_BAD_STATE; 1181 goto exit; 1182 } 1183 1184 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1185 res = TEE_ERROR_ACCESS_CONFLICT; 1186 goto exit; 1187 } 1188 1189 /* check rights of the provided buffer */ 1190 res = tee_mmu_check_access_rights(sess->ctx, 1191 TEE_MEMORY_ACCESS_READ | 1192 TEE_MEMORY_ACCESS_ANY_OWNER, 1193 (tee_uaddr_t) data, len); 1194 1195 err = tee_file_ops.write(&res, o->fd, data, len); 1196 1197 if (err != (int)len) 1198 goto exit; 1199 1200 o->info.dataPosition += len; 1201 if (o->info.dataPosition > o->info.dataSize) 1202 o->info.dataSize = o->info.dataPosition; 1203 1204 res = TEE_SUCCESS; 1205 exit: 1206 return res; 1207 } 1208 1209 TEE_Result syscall_storage_obj_trunc(uint32_t obj, size_t len) 1210 { 1211 TEE_Result res; 1212 struct tee_ta_session *sess; 1213 struct tee_obj *o; 1214 int err; 1215 tee_fs_off_t off; 1216 1217 res = tee_ta_get_current_session(&sess); 1218 if (res != TEE_SUCCESS) 1219 goto exit; 1220 1221 res = tee_obj_get(sess->ctx, obj, &o); 1222 if (res != TEE_SUCCESS) 1223 goto exit; 1224 1225 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1226 res = TEE_ERROR_BAD_STATE; 1227 goto exit; 1228 } 1229 1230 if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { 1231 res = TEE_ERROR_ACCESS_CONFLICT; 1232 goto exit; 1233 } 1234 1235 res = tee_obj_verify(sess, o); 1236 if (res != TEE_SUCCESS) 1237 goto exit; 1238 1239 off = sizeof(struct tee_svc_storage_head) + o->data_size; 1240 err = tee_file_ops.ftruncate(&res, o->fd, len + off); 1241 if (err) { 1242 if (res == TEE_ERROR_CORRUPT_OBJECT) { 1243 EMSG("Object corrupt\n"); 1244 res = tee_svc_storage_remove_corrupt_obj(sess, o); 1245 if (res != TEE_SUCCESS) 1246 goto exit; 1247 res = TEE_ERROR_CORRUPT_OBJECT; 1248 goto exit; 1249 } else 1250 res = TEE_ERROR_GENERIC; 1251 } 1252 1253 exit: 1254 return res; 1255 } 1256 1257 TEE_Result syscall_storage_obj_seek(uint32_t obj, int32_t offset, 1258 TEE_Whence whence) 1259 { 1260 TEE_Result res; 1261 struct tee_ta_session *sess; 1262 struct tee_obj *o; 1263 int fw; 1264 tee_fs_off_t off; 1265 tee_fs_off_t e_off = 0; 1266 1267 res = tee_ta_get_current_session(&sess); 1268 if (res != TEE_SUCCESS) 1269 goto exit; 1270 1271 res = tee_obj_get(sess->ctx, obj, &o); 1272 if (res != TEE_SUCCESS) 1273 goto exit; 1274 1275 if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { 1276 res = TEE_ERROR_BAD_STATE; 1277 goto exit; 1278 } 1279 1280 res = tee_obj_verify(sess, o); 1281 if (res != TEE_SUCCESS) 1282 goto exit; 1283 1284 fw = tee_svc_storage_conv_whence(whence); 1285 1286 if (whence == TEE_DATA_SEEK_SET) 1287 e_off = sizeof(struct tee_svc_storage_head) + o->data_size; 1288 1289 off = tee_file_ops.lseek(&res, o->fd, e_off + offset, fw); 1290 if (off > -1 && off >= e_off) 1291 o->info.dataPosition = off - 1292 (sizeof(struct tee_svc_storage_head) + o->data_size); 1293 else { 1294 res = TEE_ERROR_GENERIC; 1295 goto exit; 1296 } 1297 1298 res = TEE_SUCCESS; 1299 1300 exit: 1301 return res; 1302 } 1303 1304 void tee_svc_storage_close_all_enum(struct tee_ta_ctx *ctx) 1305 { 1306 struct tee_storage_enum_head *eh = &ctx->storage_enums; 1307 1308 /* disregard return value */ 1309 while (!TAILQ_EMPTY(eh)) 1310 tee_svc_close_enum(ctx, TAILQ_FIRST(eh)); 1311 } 1312