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