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