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