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