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