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