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