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