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