1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2015, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <kernel/mutex.h> 8 #include <kernel/panic.h> 9 #include <kernel/thread.h> 10 #include <mempool.h> 11 #include <mm/core_memprot.h> 12 #include <mm/tee_pager.h> 13 #include <optee_rpc_cmd.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string_ext.h> 17 #include <string.h> 18 #include <sys/queue.h> 19 #include <tee/fs_dirfile.h> 20 #include <tee/fs_htree.h> 21 #include <tee/tee_fs.h> 22 #include <tee/tee_fs_rpc.h> 23 #include <tee/tee_pobj.h> 24 #include <trace.h> 25 #include <utee_defines.h> 26 #include <util.h> 27 28 #define BLOCK_SHIFT 12 29 30 #define BLOCK_SIZE (1 << BLOCK_SHIFT) 31 32 struct tee_fs_fd { 33 struct tee_fs_htree *ht; 34 int fd; 35 struct tee_fs_dirfile_fileh dfh; 36 const TEE_UUID *uuid; 37 }; 38 39 struct tee_fs_dir { 40 struct tee_fs_dirfile_dirh *dirh; 41 int idx; 42 struct tee_fs_dirent d; 43 const TEE_UUID *uuid; 44 }; 45 46 static int pos_to_block_num(int position) 47 { 48 return position >> BLOCK_SHIFT; 49 } 50 51 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; 52 53 static void *get_tmp_block(void) 54 { 55 return mempool_alloc(mempool_default, BLOCK_SIZE); 56 } 57 58 static void put_tmp_block(void *tmp_block) 59 { 60 mempool_free(mempool_default, tmp_block); 61 } 62 63 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos, 64 const void *buf, size_t len) 65 { 66 TEE_Result res; 67 size_t start_block_num = pos_to_block_num(pos); 68 size_t end_block_num = pos_to_block_num(pos + len - 1); 69 size_t remain_bytes = len; 70 uint8_t *data_ptr = (uint8_t *)buf; 71 uint8_t *block; 72 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 73 74 /* 75 * It doesn't make sense to call this function if nothing is to be 76 * written. This also guards against end_block_num getting an 77 * unexpected value when pos == 0 and len == 0. 78 */ 79 if (!len) 80 return TEE_ERROR_BAD_PARAMETERS; 81 82 block = get_tmp_block(); 83 if (!block) 84 return TEE_ERROR_OUT_OF_MEMORY; 85 86 while (start_block_num <= end_block_num) { 87 size_t offset = pos % BLOCK_SIZE; 88 size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE); 89 90 if (size_to_write + offset > BLOCK_SIZE) 91 size_to_write = BLOCK_SIZE - offset; 92 93 if (start_block_num * BLOCK_SIZE < 94 ROUNDUP(meta->length, BLOCK_SIZE)) { 95 res = tee_fs_htree_read_block(&fdp->ht, 96 start_block_num, block); 97 if (res != TEE_SUCCESS) 98 goto exit; 99 } else { 100 memset(block, 0, BLOCK_SIZE); 101 } 102 103 if (data_ptr) 104 memcpy(block + offset, data_ptr, size_to_write); 105 else 106 memset(block + offset, 0, size_to_write); 107 108 res = tee_fs_htree_write_block(&fdp->ht, start_block_num, 109 block); 110 if (res != TEE_SUCCESS) 111 goto exit; 112 113 if (data_ptr) 114 data_ptr += size_to_write; 115 remain_bytes -= size_to_write; 116 start_block_num++; 117 pos += size_to_write; 118 } 119 120 if (pos > meta->length) { 121 meta->length = pos; 122 tee_fs_htree_meta_set_dirty(fdp->ht); 123 } 124 125 exit: 126 if (block) 127 put_tmp_block(block); 128 return res; 129 } 130 131 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx, 132 uint8_t vers, size_t *offs, size_t *size) 133 { 134 const size_t node_size = sizeof(struct tee_fs_htree_node_image); 135 const size_t block_nodes = BLOCK_SIZE / (node_size * 2); 136 size_t pbn; 137 size_t bidx; 138 139 assert(vers == 0 || vers == 1); 140 141 /* 142 * File layout 143 * [demo with input: 144 * BLOCK_SIZE = 4096, 145 * node_size = 66, 146 * block_nodes = 4096/(66*2) = 31 ] 147 * 148 * phys block 0: 149 * tee_fs_htree_image vers 0 @ offs = 0 150 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image) 151 * 152 * phys block 1: 153 * tee_fs_htree_node_image 0 vers 0 @ offs = 0 154 * tee_fs_htree_node_image 0 vers 1 @ offs = node_size 155 * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2 156 * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3 157 * ... 158 * tee_fs_htree_node_image 30 vers 0 @ offs = node_size * 60 159 * tee_fs_htree_node_image 30 vers 1 @ offs = node_size * 61 160 * 161 * phys block 2: 162 * data block 0 vers 0 163 * 164 * phys block 3: 165 * data block 0 vers 1 166 * 167 * ... 168 * phys block 62: 169 * data block 30 vers 0 170 * 171 * phys block 63: 172 * data block 30 vers 1 173 * 174 * phys block 64: 175 * tee_fs_htree_node_image 31 vers 0 @ offs = 0 176 * tee_fs_htree_node_image 31 vers 1 @ offs = node_size 177 * tee_fs_htree_node_image 32 vers 0 @ offs = node_size * 2 178 * tee_fs_htree_node_image 32 vers 1 @ offs = node_size * 3 179 * ... 180 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 60 181 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 61 182 * 183 * phys block 65: 184 * data block 31 vers 0 185 * 186 * phys block 66: 187 * data block 31 vers 1 188 * ... 189 */ 190 191 switch (type) { 192 case TEE_FS_HTREE_TYPE_HEAD: 193 *offs = sizeof(struct tee_fs_htree_image) * vers; 194 *size = sizeof(struct tee_fs_htree_image); 195 return TEE_SUCCESS; 196 case TEE_FS_HTREE_TYPE_NODE: 197 pbn = 1 + ((idx / block_nodes) * block_nodes * 2); 198 *offs = pbn * BLOCK_SIZE + 199 2 * node_size * (idx % block_nodes) + 200 node_size * vers; 201 *size = node_size; 202 return TEE_SUCCESS; 203 case TEE_FS_HTREE_TYPE_BLOCK: 204 bidx = 2 * idx + vers; 205 pbn = 2 + bidx + bidx / (block_nodes * 2 - 1); 206 *offs = pbn * BLOCK_SIZE; 207 *size = BLOCK_SIZE; 208 return TEE_SUCCESS; 209 default: 210 return TEE_ERROR_GENERIC; 211 } 212 } 213 214 static TEE_Result ree_fs_rpc_read_init(void *aux, 215 struct tee_fs_rpc_operation *op, 216 enum tee_fs_htree_type type, size_t idx, 217 uint8_t vers, void **data) 218 { 219 struct tee_fs_fd *fdp = aux; 220 TEE_Result res; 221 size_t offs; 222 size_t size; 223 224 res = get_offs_size(type, idx, vers, &offs, &size); 225 if (res != TEE_SUCCESS) 226 return res; 227 228 return tee_fs_rpc_read_init(op, OPTEE_RPC_CMD_FS, fdp->fd, 229 offs, size, data); 230 } 231 232 static TEE_Result ree_fs_rpc_write_init(void *aux, 233 struct tee_fs_rpc_operation *op, 234 enum tee_fs_htree_type type, size_t idx, 235 uint8_t vers, void **data) 236 { 237 struct tee_fs_fd *fdp = aux; 238 TEE_Result res; 239 size_t offs; 240 size_t size; 241 242 res = get_offs_size(type, idx, vers, &offs, &size); 243 if (res != TEE_SUCCESS) 244 return res; 245 246 return tee_fs_rpc_write_init(op, OPTEE_RPC_CMD_FS, fdp->fd, 247 offs, size, data); 248 } 249 250 static const struct tee_fs_htree_storage ree_fs_storage_ops = { 251 .block_size = BLOCK_SIZE, 252 .rpc_read_init = ree_fs_rpc_read_init, 253 .rpc_read_final = tee_fs_rpc_read_final, 254 .rpc_write_init = ree_fs_rpc_write_init, 255 .rpc_write_final = tee_fs_rpc_write_final, 256 }; 257 258 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, 259 tee_fs_off_t new_file_len) 260 { 261 TEE_Result res; 262 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 263 264 if ((size_t)new_file_len > meta->length) { 265 size_t ext_len = new_file_len - meta->length; 266 267 res = out_of_place_write(fdp, meta->length, NULL, ext_len); 268 if (res != TEE_SUCCESS) 269 return res; 270 } else { 271 size_t offs; 272 size_t sz; 273 274 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, 275 ROUNDUP(new_file_len, BLOCK_SIZE) / 276 BLOCK_SIZE, 1, &offs, &sz); 277 if (res != TEE_SUCCESS) 278 return res; 279 280 res = tee_fs_htree_truncate(&fdp->ht, 281 new_file_len / BLOCK_SIZE); 282 if (res != TEE_SUCCESS) 283 return res; 284 285 res = tee_fs_rpc_truncate(OPTEE_RPC_CMD_FS, fdp->fd, 286 offs + sz); 287 if (res != TEE_SUCCESS) 288 return res; 289 290 meta->length = new_file_len; 291 tee_fs_htree_meta_set_dirty(fdp->ht); 292 } 293 294 return TEE_SUCCESS; 295 } 296 297 static TEE_Result ree_fs_read_primitive(struct tee_file_handle *fh, size_t pos, 298 void *buf, size_t *len) 299 { 300 TEE_Result res; 301 int start_block_num; 302 int end_block_num; 303 size_t remain_bytes; 304 uint8_t *data_ptr = buf; 305 uint8_t *block = NULL; 306 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 307 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 308 309 remain_bytes = *len; 310 if ((pos + remain_bytes) < remain_bytes || pos > meta->length) 311 remain_bytes = 0; 312 else if (pos + remain_bytes > meta->length) 313 remain_bytes = meta->length - pos; 314 315 *len = remain_bytes; 316 317 if (!remain_bytes) { 318 res = TEE_SUCCESS; 319 goto exit; 320 } 321 322 start_block_num = pos_to_block_num(pos); 323 end_block_num = pos_to_block_num(pos + remain_bytes - 1); 324 325 block = get_tmp_block(); 326 if (!block) { 327 res = TEE_ERROR_OUT_OF_MEMORY; 328 goto exit; 329 } 330 331 while (start_block_num <= end_block_num) { 332 size_t offset = pos % BLOCK_SIZE; 333 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); 334 335 if (size_to_read + offset > BLOCK_SIZE) 336 size_to_read = BLOCK_SIZE - offset; 337 338 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block); 339 if (res != TEE_SUCCESS) 340 goto exit; 341 342 memcpy(data_ptr, block + offset, size_to_read); 343 344 data_ptr += size_to_read; 345 remain_bytes -= size_to_read; 346 pos += size_to_read; 347 348 start_block_num++; 349 } 350 res = TEE_SUCCESS; 351 exit: 352 if (block) 353 put_tmp_block(block); 354 return res; 355 } 356 357 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos, 358 void *buf, size_t *len) 359 { 360 TEE_Result res; 361 362 mutex_lock(&ree_fs_mutex); 363 res = ree_fs_read_primitive(fh, pos, buf, len); 364 mutex_unlock(&ree_fs_mutex); 365 366 return res; 367 } 368 369 static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos, 370 const void *buf, size_t len) 371 { 372 TEE_Result res; 373 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 374 size_t file_size; 375 376 if (!len) 377 return TEE_SUCCESS; 378 379 file_size = tee_fs_htree_get_meta(fdp->ht)->length; 380 381 if ((pos + len) < len) 382 return TEE_ERROR_BAD_PARAMETERS; 383 384 if (file_size < pos) { 385 res = ree_fs_ftruncate_internal(fdp, pos); 386 if (res != TEE_SUCCESS) 387 return res; 388 } 389 390 return out_of_place_write(fdp, pos, buf, len); 391 } 392 393 static TEE_Result ree_fs_open_primitive(bool create, uint8_t *hash, 394 const TEE_UUID *uuid, 395 struct tee_fs_dirfile_fileh *dfh, 396 struct tee_file_handle **fh) 397 { 398 TEE_Result res; 399 struct tee_fs_fd *fdp; 400 401 fdp = calloc(1, sizeof(struct tee_fs_fd)); 402 if (!fdp) 403 return TEE_ERROR_OUT_OF_MEMORY; 404 fdp->fd = -1; 405 fdp->uuid = uuid; 406 407 if (create) 408 res = tee_fs_rpc_create_dfh(OPTEE_RPC_CMD_FS, 409 dfh, &fdp->fd); 410 else 411 res = tee_fs_rpc_open_dfh(OPTEE_RPC_CMD_FS, dfh, &fdp->fd); 412 413 if (res != TEE_SUCCESS) 414 goto out; 415 416 res = tee_fs_htree_open(create, hash, uuid, &ree_fs_storage_ops, 417 fdp, &fdp->ht); 418 out: 419 if (res == TEE_SUCCESS) { 420 if (dfh) 421 fdp->dfh = *dfh; 422 else 423 fdp->dfh.idx = -1; 424 *fh = (struct tee_file_handle *)fdp; 425 } else { 426 if (fdp->fd != -1) 427 tee_fs_rpc_close(OPTEE_RPC_CMD_FS, fdp->fd); 428 if (create) 429 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, dfh); 430 free(fdp); 431 } 432 433 return res; 434 } 435 436 static void ree_fs_close_primitive(struct tee_file_handle *fh) 437 { 438 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 439 440 if (fdp) { 441 tee_fs_htree_close(&fdp->ht); 442 tee_fs_rpc_close(OPTEE_RPC_CMD_FS, fdp->fd); 443 free(fdp); 444 } 445 } 446 447 static TEE_Result ree_dirf_commit_writes(struct tee_file_handle *fh, 448 uint8_t *hash) 449 { 450 TEE_Result res; 451 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 452 453 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 454 455 if (!res && hash) 456 memcpy(hash, fdp->dfh.hash, sizeof(fdp->dfh.hash)); 457 458 return res; 459 } 460 461 static const struct tee_fs_dirfile_operations ree_dirf_ops = { 462 .open = ree_fs_open_primitive, 463 .close = ree_fs_close_primitive, 464 .read = ree_fs_read_primitive, 465 .write = ree_fs_write_primitive, 466 .commit_writes = ree_dirf_commit_writes, 467 }; 468 469 static struct tee_fs_dirfile_dirh *ree_fs_dirh; 470 static size_t ree_fs_dirh_refcount; 471 472 #ifdef CFG_RPMB_FS 473 static struct tee_file_handle *ree_fs_rpmb_fh; 474 475 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh) 476 { 477 TEE_Result res; 478 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 479 uint8_t *hashp = NULL; 480 const char fname[] = "dirfile.db.hash"; 481 482 res = tee_rpmb_fs_raw_open(fname, false, &ree_fs_rpmb_fh); 483 if (!res) { 484 size_t l = sizeof(hash); 485 486 res = rpmb_fs_ops.read(ree_fs_rpmb_fh, 0, hash, &l); 487 if (res) 488 return res; 489 if (l == sizeof(hash)) 490 hashp = hash; 491 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 492 res = tee_rpmb_fs_raw_open(fname, true, &ree_fs_rpmb_fh); 493 } 494 if (res) 495 return res; 496 497 res = tee_fs_dirfile_open(false, hashp, &ree_dirf_ops, dirh); 498 if (res == TEE_ERROR_ITEM_NOT_FOUND) 499 res = tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh); 500 501 if (res) 502 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 503 504 return res; 505 } 506 507 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 508 { 509 TEE_Result res; 510 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 511 512 res = tee_fs_dirfile_commit_writes(dirh, hash); 513 if (res) 514 return res; 515 return rpmb_fs_ops.write(ree_fs_rpmb_fh, 0, hash, sizeof(hash)); 516 } 517 518 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 519 { 520 tee_fs_dirfile_close(*dirh); 521 *dirh = NULL; 522 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 523 } 524 525 #else /*!CFG_RPMB_FS*/ 526 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh) 527 { 528 TEE_Result res; 529 530 res = tee_fs_dirfile_open(false, NULL, &ree_dirf_ops, dirh); 531 if (res == TEE_ERROR_ITEM_NOT_FOUND) 532 return tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh); 533 534 return res; 535 } 536 537 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 538 { 539 return tee_fs_dirfile_commit_writes(dirh, NULL); 540 } 541 542 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 543 { 544 tee_fs_dirfile_close(*dirh); 545 *dirh = NULL; 546 } 547 #endif /*!CFG_RPMB_FS*/ 548 549 static TEE_Result get_dirh(struct tee_fs_dirfile_dirh **dirh) 550 { 551 if (!ree_fs_dirh) { 552 TEE_Result res = open_dirh(&ree_fs_dirh); 553 554 if (res) { 555 *dirh = NULL; 556 return res; 557 } 558 } 559 ree_fs_dirh_refcount++; 560 assert(ree_fs_dirh); 561 assert(ree_fs_dirh_refcount); 562 *dirh = ree_fs_dirh; 563 return TEE_SUCCESS; 564 } 565 566 static void put_dirh_primitive(bool close) 567 { 568 assert(ree_fs_dirh_refcount); 569 570 /* 571 * During the execution of one of the ree_fs_ops ree_fs_dirh is 572 * guareteed to be a valid pointer. But when the fop has returned 573 * another thread may get an error or something causing that fop 574 * to do a put with close=1. 575 * 576 * For all fops but ree_fs_close() there's a call to get_dirh() to 577 * get a new dirh which will open it again if it was closed before. 578 * But in the ree_fs_close() case there's no call to get_dirh() 579 * only to this function, put_dirh_primitive(), and in this case 580 * ree_fs_dirh may actually be NULL. 581 */ 582 ree_fs_dirh_refcount--; 583 if (ree_fs_dirh && (!ree_fs_dirh_refcount || close)) 584 close_dirh(&ree_fs_dirh); 585 } 586 587 static void put_dirh(struct tee_fs_dirfile_dirh *dirh, bool close) 588 { 589 if (dirh) { 590 assert(dirh == ree_fs_dirh); 591 put_dirh_primitive(close); 592 } 593 } 594 595 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size, 596 struct tee_file_handle **fh) 597 { 598 TEE_Result res; 599 struct tee_fs_dirfile_dirh *dirh = NULL; 600 struct tee_fs_dirfile_fileh dfh; 601 602 mutex_lock(&ree_fs_mutex); 603 604 res = get_dirh(&dirh); 605 if (res != TEE_SUCCESS) 606 goto out; 607 608 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 609 &dfh); 610 if (res != TEE_SUCCESS) 611 goto out; 612 613 res = ree_fs_open_primitive(false, dfh.hash, &po->uuid, &dfh, fh); 614 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 615 /* 616 * If the object isn't found someone has tampered with it, 617 * treat it as corrupt. 618 */ 619 res = TEE_ERROR_CORRUPT_OBJECT; 620 } else if (!res && size) { 621 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 622 623 *size = tee_fs_htree_get_meta(fdp->ht)->length; 624 } 625 626 out: 627 if (res) 628 put_dirh(dirh, false); 629 mutex_unlock(&ree_fs_mutex); 630 631 return res; 632 } 633 634 static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh, 635 struct tee_fs_fd *fdp, struct tee_pobj *po, 636 bool overwrite) 637 { 638 TEE_Result res; 639 bool have_old_dfh = false; 640 struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 }; 641 642 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 643 &old_dfh); 644 if (!overwrite && !res) 645 return TEE_ERROR_ACCESS_CONFLICT; 646 647 if (!res) 648 have_old_dfh = true; 649 650 /* 651 * If old_dfh wasn't found, the idx will be -1 and 652 * tee_fs_dirfile_rename() will allocate a new index. 653 */ 654 fdp->dfh.idx = old_dfh.idx; 655 old_dfh.idx = -1; 656 res = tee_fs_dirfile_rename(dirh, &po->uuid, &fdp->dfh, 657 po->obj_id, po->obj_id_len); 658 if (res) 659 return res; 660 661 res = commit_dirh_writes(dirh); 662 if (res) 663 return res; 664 665 if (have_old_dfh) 666 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &old_dfh); 667 668 return TEE_SUCCESS; 669 } 670 671 static void ree_fs_close(struct tee_file_handle **fh) 672 { 673 if (*fh) { 674 mutex_lock(&ree_fs_mutex); 675 put_dirh_primitive(false); 676 ree_fs_close_primitive(*fh); 677 *fh = NULL; 678 mutex_unlock(&ree_fs_mutex); 679 680 } 681 } 682 683 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite, 684 const void *head, size_t head_size, 685 const void *attr, size_t attr_size, 686 const void *data, size_t data_size, 687 struct tee_file_handle **fh) 688 { 689 struct tee_fs_fd *fdp; 690 struct tee_fs_dirfile_dirh *dirh = NULL; 691 struct tee_fs_dirfile_fileh dfh; 692 TEE_Result res; 693 size_t pos = 0; 694 695 *fh = NULL; 696 mutex_lock(&ree_fs_mutex); 697 698 res = get_dirh(&dirh); 699 if (res) 700 goto out; 701 702 res = tee_fs_dirfile_get_tmp(dirh, &dfh); 703 if (res) 704 goto out; 705 706 res = ree_fs_open_primitive(true, dfh.hash, &po->uuid, &dfh, fh); 707 if (res) 708 goto out; 709 710 if (head && head_size) { 711 res = ree_fs_write_primitive(*fh, pos, head, head_size); 712 if (res) 713 goto out; 714 pos += head_size; 715 } 716 717 if (attr && attr_size) { 718 res = ree_fs_write_primitive(*fh, pos, attr, attr_size); 719 if (res) 720 goto out; 721 pos += attr_size; 722 } 723 724 if (data && data_size) { 725 res = ree_fs_write_primitive(*fh, pos, data, data_size); 726 if (res) 727 goto out; 728 } 729 730 fdp = (struct tee_fs_fd *)*fh; 731 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 732 if (res) 733 goto out; 734 735 res = set_name(dirh, fdp, po, overwrite); 736 out: 737 if (res) { 738 put_dirh(dirh, true); 739 if (*fh) { 740 ree_fs_close_primitive(*fh); 741 *fh = NULL; 742 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh); 743 } 744 } 745 mutex_unlock(&ree_fs_mutex); 746 747 return res; 748 } 749 750 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, 751 const void *buf, size_t len) 752 { 753 TEE_Result res; 754 struct tee_fs_dirfile_dirh *dirh = NULL; 755 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 756 757 mutex_lock(&ree_fs_mutex); 758 759 res = get_dirh(&dirh); 760 if (res) 761 goto out; 762 763 res = ree_fs_write_primitive(fh, pos, buf, len); 764 if (res) 765 goto out; 766 767 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 768 if (res) 769 goto out; 770 771 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 772 if (res) 773 goto out; 774 res = commit_dirh_writes(dirh); 775 out: 776 put_dirh(dirh, res); 777 mutex_unlock(&ree_fs_mutex); 778 779 return res; 780 } 781 782 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new, 783 bool overwrite) 784 { 785 TEE_Result res; 786 struct tee_fs_dirfile_dirh *dirh = NULL; 787 struct tee_fs_dirfile_fileh dfh; 788 struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 }; 789 790 if (!new) 791 return TEE_ERROR_BAD_PARAMETERS; 792 793 mutex_lock(&ree_fs_mutex); 794 res = get_dirh(&dirh); 795 if (res) 796 goto out; 797 798 res = tee_fs_dirfile_find(dirh, &new->uuid, new->obj_id, 799 new->obj_id_len, &remove_dfh); 800 if (!res && !overwrite) { 801 res = TEE_ERROR_ACCESS_CONFLICT; 802 goto out; 803 } 804 805 res = tee_fs_dirfile_find(dirh, &old->uuid, old->obj_id, 806 old->obj_id_len, &dfh); 807 if (res) 808 goto out; 809 810 res = tee_fs_dirfile_rename(dirh, &new->uuid, &dfh, new->obj_id, 811 new->obj_id_len); 812 if (res) 813 goto out; 814 815 if (remove_dfh.idx != -1) { 816 res = tee_fs_dirfile_remove(dirh, &remove_dfh); 817 if (res) 818 goto out; 819 } 820 821 res = commit_dirh_writes(dirh); 822 if (res) 823 goto out; 824 825 if (remove_dfh.idx != -1) 826 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &remove_dfh); 827 828 out: 829 put_dirh(dirh, res); 830 mutex_unlock(&ree_fs_mutex); 831 832 return res; 833 834 } 835 836 static TEE_Result ree_fs_remove(struct tee_pobj *po) 837 { 838 TEE_Result res; 839 struct tee_fs_dirfile_dirh *dirh = NULL; 840 struct tee_fs_dirfile_fileh dfh; 841 842 mutex_lock(&ree_fs_mutex); 843 res = get_dirh(&dirh); 844 if (res) 845 goto out; 846 847 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 848 &dfh); 849 if (res) 850 goto out; 851 852 res = tee_fs_dirfile_remove(dirh, &dfh); 853 if (res) 854 goto out; 855 856 res = commit_dirh_writes(dirh); 857 if (res) 858 goto out; 859 860 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh); 861 862 assert(tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 863 &dfh)); 864 out: 865 put_dirh(dirh, res); 866 mutex_unlock(&ree_fs_mutex); 867 868 return res; 869 } 870 871 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 872 { 873 TEE_Result res; 874 struct tee_fs_dirfile_dirh *dirh = NULL; 875 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 876 877 mutex_lock(&ree_fs_mutex); 878 879 res = get_dirh(&dirh); 880 if (res) 881 goto out; 882 883 res = ree_fs_ftruncate_internal(fdp, len); 884 if (res) 885 goto out; 886 887 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 888 if (res) 889 goto out; 890 891 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 892 if (res) 893 goto out; 894 res = commit_dirh_writes(dirh); 895 out: 896 put_dirh(dirh, res); 897 mutex_unlock(&ree_fs_mutex); 898 899 return res; 900 } 901 902 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid, 903 struct tee_fs_dir **dir) 904 905 { 906 TEE_Result res; 907 struct tee_fs_dir *d = calloc(1, sizeof(*d)); 908 909 if (!d) 910 return TEE_ERROR_OUT_OF_MEMORY; 911 912 d->uuid = uuid; 913 914 mutex_lock(&ree_fs_mutex); 915 916 res = get_dirh(&d->dirh); 917 if (res) 918 goto out; 919 920 /* See that there's at least one file */ 921 d->idx = -1; 922 d->d.oidlen = sizeof(d->d.oid); 923 res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid, 924 &d->d.oidlen); 925 d->idx = -1; 926 927 out: 928 if (!res) { 929 *dir = d; 930 } else { 931 if (d) 932 put_dirh(d->dirh, false); 933 free(d); 934 } 935 mutex_unlock(&ree_fs_mutex); 936 937 return res; 938 } 939 940 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 941 { 942 if (d) { 943 mutex_lock(&ree_fs_mutex); 944 945 put_dirh(d->dirh, false); 946 free(d); 947 948 mutex_unlock(&ree_fs_mutex); 949 } 950 } 951 952 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 953 struct tee_fs_dirent **ent) 954 { 955 TEE_Result res; 956 957 mutex_lock(&ree_fs_mutex); 958 959 d->d.oidlen = sizeof(d->d.oid); 960 res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid, 961 &d->d.oidlen); 962 if (res == TEE_SUCCESS) 963 *ent = &d->d; 964 965 mutex_unlock(&ree_fs_mutex); 966 967 return res; 968 } 969 970 const struct tee_file_operations ree_fs_ops = { 971 .open = ree_fs_open, 972 .create = ree_fs_create, 973 .close = ree_fs_close, 974 .read = ree_fs_read, 975 .write = ree_fs_write, 976 .truncate = ree_fs_truncate, 977 .rename = ree_fs_rename, 978 .remove = ree_fs_remove, 979 .opendir = ree_fs_opendir_rpc, 980 .closedir = ree_fs_closedir_rpc, 981 .readdir = ree_fs_readdir_rpc, 982 }; 983