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