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