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