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 if (!tee_fs_dirfile_open(false, hashp, &ree_dirf_ops, dirh)) 498 return TEE_SUCCESS; 499 500 res = tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh); 501 if (res) 502 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 503 return res; 504 } 505 506 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 507 { 508 TEE_Result res; 509 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 510 511 res = tee_fs_dirfile_commit_writes(dirh, hash); 512 if (res) 513 return res; 514 return rpmb_fs_ops.write(ree_fs_rpmb_fh, 0, hash, sizeof(hash)); 515 } 516 517 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 518 { 519 tee_fs_dirfile_close(*dirh); 520 *dirh = NULL; 521 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 522 } 523 524 #else /*!CFG_RPMB_FS*/ 525 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh) 526 { 527 if (!tee_fs_dirfile_open(false, NULL, &ree_dirf_ops, dirh)) 528 return TEE_SUCCESS; 529 return tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh); 530 } 531 532 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 533 { 534 return tee_fs_dirfile_commit_writes(dirh, NULL); 535 } 536 537 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 538 { 539 tee_fs_dirfile_close(*dirh); 540 *dirh = NULL; 541 } 542 #endif /*!CFG_RPMB_FS*/ 543 544 static TEE_Result get_dirh(struct tee_fs_dirfile_dirh **dirh) 545 { 546 if (!ree_fs_dirh) { 547 TEE_Result res = open_dirh(&ree_fs_dirh); 548 549 if (res) { 550 *dirh = NULL; 551 return res; 552 } 553 } 554 ree_fs_dirh_refcount++; 555 assert(ree_fs_dirh); 556 assert(ree_fs_dirh_refcount); 557 *dirh = ree_fs_dirh; 558 return TEE_SUCCESS; 559 } 560 561 static void put_dirh_primitive(bool close) 562 { 563 assert(ree_fs_dirh_refcount); 564 565 /* 566 * During the execution of one of the ree_fs_ops ree_fs_dirh is 567 * guareteed to be a valid pointer. But when the fop has returned 568 * another thread may get an error or something causing that fop 569 * to do a put with close=1. 570 * 571 * For all fops but ree_fs_close() there's a call to get_dirh() to 572 * get a new dirh which will open it again if it was closed before. 573 * But in the ree_fs_close() case there's no call to get_dirh() 574 * only to this function, put_dirh_primitive(), and in this case 575 * ree_fs_dirh may actually be NULL. 576 */ 577 ree_fs_dirh_refcount--; 578 if (ree_fs_dirh && (!ree_fs_dirh_refcount || close)) 579 close_dirh(&ree_fs_dirh); 580 } 581 582 static void put_dirh(struct tee_fs_dirfile_dirh *dirh, bool close) 583 { 584 if (dirh) { 585 assert(dirh == ree_fs_dirh); 586 put_dirh_primitive(close); 587 } 588 } 589 590 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size, 591 struct tee_file_handle **fh) 592 { 593 TEE_Result res; 594 struct tee_fs_dirfile_dirh *dirh = NULL; 595 struct tee_fs_dirfile_fileh dfh; 596 597 mutex_lock(&ree_fs_mutex); 598 599 res = get_dirh(&dirh); 600 if (res != TEE_SUCCESS) 601 goto out; 602 603 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 604 &dfh); 605 if (res != TEE_SUCCESS) 606 goto out; 607 608 res = ree_fs_open_primitive(false, dfh.hash, &po->uuid, &dfh, fh); 609 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 610 /* 611 * If the object isn't found someone has tampered with it, 612 * treat it as corrupt. 613 */ 614 res = TEE_ERROR_CORRUPT_OBJECT; 615 } else if (!res && size) { 616 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 617 618 *size = tee_fs_htree_get_meta(fdp->ht)->length; 619 } 620 621 out: 622 if (res) 623 put_dirh(dirh, false); 624 mutex_unlock(&ree_fs_mutex); 625 626 return res; 627 } 628 629 static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh, 630 struct tee_fs_fd *fdp, struct tee_pobj *po, 631 bool overwrite) 632 { 633 TEE_Result res; 634 bool have_old_dfh = false; 635 struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 }; 636 637 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 638 &old_dfh); 639 if (!overwrite && !res) 640 return TEE_ERROR_ACCESS_CONFLICT; 641 642 if (!res) 643 have_old_dfh = true; 644 645 /* 646 * If old_dfh wasn't found, the idx will be -1 and 647 * tee_fs_dirfile_rename() will allocate a new index. 648 */ 649 fdp->dfh.idx = old_dfh.idx; 650 old_dfh.idx = -1; 651 res = tee_fs_dirfile_rename(dirh, &po->uuid, &fdp->dfh, 652 po->obj_id, po->obj_id_len); 653 if (res) 654 return res; 655 656 res = commit_dirh_writes(dirh); 657 if (res) 658 return res; 659 660 if (have_old_dfh) 661 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &old_dfh); 662 663 return TEE_SUCCESS; 664 } 665 666 static void ree_fs_close(struct tee_file_handle **fh) 667 { 668 if (*fh) { 669 mutex_lock(&ree_fs_mutex); 670 put_dirh_primitive(false); 671 ree_fs_close_primitive(*fh); 672 *fh = NULL; 673 mutex_unlock(&ree_fs_mutex); 674 675 } 676 } 677 678 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite, 679 const void *head, size_t head_size, 680 const void *attr, size_t attr_size, 681 const void *data, size_t data_size, 682 struct tee_file_handle **fh) 683 { 684 struct tee_fs_fd *fdp; 685 struct tee_fs_dirfile_dirh *dirh = NULL; 686 struct tee_fs_dirfile_fileh dfh; 687 TEE_Result res; 688 size_t pos = 0; 689 690 *fh = NULL; 691 mutex_lock(&ree_fs_mutex); 692 693 res = get_dirh(&dirh); 694 if (res) 695 goto out; 696 697 res = tee_fs_dirfile_get_tmp(dirh, &dfh); 698 if (res) 699 goto out; 700 701 res = ree_fs_open_primitive(true, dfh.hash, &po->uuid, &dfh, fh); 702 if (res) 703 goto out; 704 705 if (head && head_size) { 706 res = ree_fs_write_primitive(*fh, pos, head, head_size); 707 if (res) 708 goto out; 709 pos += head_size; 710 } 711 712 if (attr && attr_size) { 713 res = ree_fs_write_primitive(*fh, pos, attr, attr_size); 714 if (res) 715 goto out; 716 pos += attr_size; 717 } 718 719 if (data && data_size) { 720 res = ree_fs_write_primitive(*fh, pos, data, data_size); 721 if (res) 722 goto out; 723 } 724 725 fdp = (struct tee_fs_fd *)*fh; 726 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 727 if (res) 728 goto out; 729 730 res = set_name(dirh, fdp, po, overwrite); 731 out: 732 if (res) { 733 put_dirh(dirh, true); 734 if (*fh) { 735 ree_fs_close_primitive(*fh); 736 *fh = NULL; 737 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh); 738 } 739 } 740 mutex_unlock(&ree_fs_mutex); 741 742 return res; 743 } 744 745 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, 746 const void *buf, size_t len) 747 { 748 TEE_Result res; 749 struct tee_fs_dirfile_dirh *dirh = NULL; 750 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 751 752 mutex_lock(&ree_fs_mutex); 753 754 res = get_dirh(&dirh); 755 if (res) 756 goto out; 757 758 res = ree_fs_write_primitive(fh, pos, buf, len); 759 if (res) 760 goto out; 761 762 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 763 if (res) 764 goto out; 765 766 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 767 if (res) 768 goto out; 769 res = commit_dirh_writes(dirh); 770 out: 771 put_dirh(dirh, res); 772 mutex_unlock(&ree_fs_mutex); 773 774 return res; 775 } 776 777 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new, 778 bool overwrite) 779 { 780 TEE_Result res; 781 struct tee_fs_dirfile_dirh *dirh = NULL; 782 struct tee_fs_dirfile_fileh dfh; 783 struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 }; 784 785 if (!new) 786 return TEE_ERROR_BAD_PARAMETERS; 787 788 mutex_lock(&ree_fs_mutex); 789 res = get_dirh(&dirh); 790 if (res) 791 goto out; 792 793 res = tee_fs_dirfile_find(dirh, &new->uuid, new->obj_id, 794 new->obj_id_len, &remove_dfh); 795 if (!res && !overwrite) { 796 res = TEE_ERROR_ACCESS_CONFLICT; 797 goto out; 798 } 799 800 res = tee_fs_dirfile_find(dirh, &old->uuid, old->obj_id, 801 old->obj_id_len, &dfh); 802 if (res) 803 goto out; 804 805 res = tee_fs_dirfile_rename(dirh, &new->uuid, &dfh, new->obj_id, 806 new->obj_id_len); 807 if (res) 808 goto out; 809 810 if (remove_dfh.idx != -1) { 811 res = tee_fs_dirfile_remove(dirh, &remove_dfh); 812 if (res) 813 goto out; 814 } 815 816 res = commit_dirh_writes(dirh); 817 if (res) 818 goto out; 819 820 if (remove_dfh.idx != -1) 821 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &remove_dfh); 822 823 out: 824 put_dirh(dirh, res); 825 mutex_unlock(&ree_fs_mutex); 826 827 return res; 828 829 } 830 831 static TEE_Result ree_fs_remove(struct tee_pobj *po) 832 { 833 TEE_Result res; 834 struct tee_fs_dirfile_dirh *dirh = NULL; 835 struct tee_fs_dirfile_fileh dfh; 836 837 mutex_lock(&ree_fs_mutex); 838 res = get_dirh(&dirh); 839 if (res) 840 goto out; 841 842 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 843 &dfh); 844 if (res) 845 goto out; 846 847 res = tee_fs_dirfile_remove(dirh, &dfh); 848 if (res) 849 goto out; 850 851 res = commit_dirh_writes(dirh); 852 if (res) 853 goto out; 854 855 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh); 856 857 assert(tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 858 &dfh)); 859 out: 860 put_dirh(dirh, res); 861 mutex_unlock(&ree_fs_mutex); 862 863 return res; 864 } 865 866 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 867 { 868 TEE_Result res; 869 struct tee_fs_dirfile_dirh *dirh = NULL; 870 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 871 872 mutex_lock(&ree_fs_mutex); 873 874 res = get_dirh(&dirh); 875 if (res) 876 goto out; 877 878 res = ree_fs_ftruncate_internal(fdp, len); 879 if (res) 880 goto out; 881 882 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 883 if (res) 884 goto out; 885 886 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 887 if (res) 888 goto out; 889 res = commit_dirh_writes(dirh); 890 out: 891 put_dirh(dirh, res); 892 mutex_unlock(&ree_fs_mutex); 893 894 return res; 895 } 896 897 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid, 898 struct tee_fs_dir **dir) 899 900 { 901 TEE_Result res; 902 struct tee_fs_dir *d = calloc(1, sizeof(*d)); 903 904 if (!d) 905 return TEE_ERROR_OUT_OF_MEMORY; 906 907 d->uuid = uuid; 908 909 mutex_lock(&ree_fs_mutex); 910 911 res = get_dirh(&d->dirh); 912 if (res) 913 goto out; 914 915 /* See that there's at least one file */ 916 d->idx = -1; 917 d->d.oidlen = sizeof(d->d.oid); 918 res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid, 919 &d->d.oidlen); 920 d->idx = -1; 921 922 out: 923 if (!res) { 924 *dir = d; 925 } else { 926 if (d) 927 put_dirh(d->dirh, false); 928 free(d); 929 } 930 mutex_unlock(&ree_fs_mutex); 931 932 return res; 933 } 934 935 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 936 { 937 if (d) { 938 mutex_lock(&ree_fs_mutex); 939 940 put_dirh(d->dirh, false); 941 free(d); 942 943 mutex_unlock(&ree_fs_mutex); 944 } 945 } 946 947 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 948 struct tee_fs_dirent **ent) 949 { 950 TEE_Result res; 951 952 mutex_lock(&ree_fs_mutex); 953 954 d->d.oidlen = sizeof(d->d.oid); 955 res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid, 956 &d->d.oidlen); 957 if (res == TEE_SUCCESS) 958 *ent = &d->d; 959 960 mutex_unlock(&ree_fs_mutex); 961 962 return res; 963 } 964 965 const struct tee_file_operations ree_fs_ops = { 966 .open = ree_fs_open, 967 .create = ree_fs_create, 968 .close = ree_fs_close, 969 .read = ree_fs_read, 970 .write = ree_fs_write, 971 .truncate = ree_fs_truncate, 972 .rename = ree_fs_rename, 973 .remove = ree_fs_remove, 974 .opendir = ree_fs_opendir_rpc, 975 .closedir = ree_fs_closedir_rpc, 976 .readdir = ree_fs_readdir_rpc, 977 }; 978