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