1 /* 2 * Copyright (c) 2015, Linaro Limited 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <assert.h> 29 #include <kernel/thread.h> 30 #include <kernel/handle.h> 31 #include <kernel/mutex.h> 32 #include <kernel/panic.h> 33 #include <mm/core_memprot.h> 34 #include <optee_msg.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <string_ext.h> 39 #include <sys/queue.h> 40 #include <tee/tee_cryp_provider.h> 41 #include <tee/tee_fs.h> 42 #include <tee/tee_fs_defs.h> 43 #include <tee/tee_fs_rpc.h> 44 #include <tee/tee_fs_key_manager.h> 45 #include <trace.h> 46 #include <utee_defines.h> 47 #include <util.h> 48 49 #define BLOCK_FILE_SHIFT 12 50 51 #define BLOCK_FILE_SIZE (1 << BLOCK_FILE_SHIFT) 52 53 #define MAX_NUM_CACHED_BLOCKS 1 54 55 #define NUM_BLOCKS_PER_FILE 1024 56 57 #define MAX_FILE_SIZE (BLOCK_FILE_SIZE * NUM_BLOCKS_PER_FILE) 58 59 struct tee_fs_file_info { 60 size_t length; 61 uint32_t backup_version_table[NUM_BLOCKS_PER_FILE / 32]; 62 }; 63 64 struct tee_fs_file_meta { 65 struct tee_fs_file_info info; 66 uint8_t encrypted_fek[TEE_FS_KM_FEK_SIZE]; 67 uint8_t backup_version; 68 }; 69 70 TAILQ_HEAD(block_head, block); 71 72 struct block { 73 TAILQ_ENTRY(block) list; 74 int block_num; 75 uint8_t *data; 76 size_t data_size; 77 }; 78 79 struct block_cache { 80 struct block_head block_lru; 81 uint8_t cached_block_num; 82 }; 83 84 struct tee_fs_fd { 85 struct tee_fs_file_meta *meta; 86 tee_fs_off_t pos; 87 uint32_t flags; 88 int fd; 89 bool is_new_file; 90 char *filename; 91 struct block_cache block_cache; 92 }; 93 94 static inline int pos_to_block_num(int position) 95 { 96 return position >> BLOCK_FILE_SHIFT; 97 } 98 99 static inline int get_last_block_num(size_t size) 100 { 101 return pos_to_block_num(size - 1); 102 } 103 104 static inline uint8_t get_backup_version_of_block( 105 struct tee_fs_file_meta *meta, 106 size_t block_num) 107 { 108 uint32_t index = (block_num / 32); 109 uint32_t block_mask = 1 << (block_num % 32); 110 111 return !!(meta->info.backup_version_table[index] & block_mask); 112 } 113 114 static inline void toggle_backup_version_of_block( 115 struct tee_fs_file_meta *meta, 116 size_t block_num) 117 { 118 uint32_t index = (block_num / 32); 119 uint32_t block_mask = 1 << (block_num % 32); 120 121 meta->info.backup_version_table[index] ^= block_mask; 122 } 123 124 struct block_operations { 125 126 /* 127 * Read a block from REE File System which is corresponding 128 * to the given block_num. 129 */ 130 struct block *(*read)(struct tee_fs_fd *fdp, int block_num); 131 132 /* 133 * Write the given block to REE File System 134 */ 135 int (*write)(struct tee_fs_fd *fdp, struct block *b, 136 struct tee_fs_file_meta *new_meta); 137 }; 138 139 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER; 140 141 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; 142 143 /* 144 * We split a TEE file into multiple blocks and store them 145 * on REE filesystem. A TEE file is represented by a REE file 146 * called meta and a number of REE files called blocks. Meta 147 * file is used for storing file information, e.g. file size 148 * and backup version of each block. 149 * 150 * REE files naming rule is as follows: 151 * 152 * <tee_file_name>/meta.<backup_version> 153 * <tee_file_name>/block0.<backup_version> 154 * ... 155 * <tee_file_name>/block15.<backup_version> 156 * 157 * Backup_version is used to support atomic update operation. 158 * Original file will not be updated, instead we create a new 159 * version of the same file and update the new file instead. 160 * 161 * The backup_version of each block file is stored in meta 162 * file, the meta file itself also has backup_version, the update is 163 * successful after new version of meta has been written. 164 */ 165 #define REE_FS_NAME_MAX (TEE_FS_NAME_MAX + 20) 166 167 168 static int ree_fs_mkdir_rpc(const char *path, tee_fs_mode_t mode) 169 { 170 return tee_fs_rpc_mkdir(OPTEE_MSG_RPC_CMD_FS, path, mode); 171 } 172 173 static struct tee_fs_dir *ree_fs_opendir_rpc(const char *name) 174 { 175 return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name); 176 } 177 178 static int ree_fs_closedir_rpc(struct tee_fs_dir *d) 179 { 180 return tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d); 181 } 182 183 static struct tee_fs_dirent *ree_fs_readdir_rpc(struct tee_fs_dir *d) 184 { 185 return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d); 186 } 187 188 static int ree_fs_rmdir_rpc(const char *name) 189 { 190 return tee_fs_rpc_rmdir(OPTEE_MSG_RPC_CMD_FS, name); 191 } 192 193 static int ree_fs_access_rpc(const char *name, int mode) 194 { 195 return tee_fs_rpc_access(OPTEE_MSG_RPC_CMD_FS, name, mode); 196 } 197 198 static int get_file_length(int fd, size_t *length) 199 { 200 size_t file_len; 201 int res; 202 203 assert(length); 204 *length = 0; 205 206 res = tee_fs_rpc_lseek(OPTEE_MSG_RPC_CMD_FS, fd, 0, TEE_FS_SEEK_END); 207 if (res < 0) 208 return res; 209 210 file_len = res; 211 212 res = tee_fs_rpc_lseek(OPTEE_MSG_RPC_CMD_FS, fd, 0, TEE_FS_SEEK_SET); 213 if (res < 0) 214 return res; 215 216 *length = file_len; 217 return 0; 218 } 219 220 static void get_meta_filepath(const char *file, int version, 221 char *meta_path) 222 { 223 snprintf(meta_path, REE_FS_NAME_MAX, "%s/meta.%d", 224 file, version); 225 } 226 227 static void get_block_filepath(const char *file, size_t block_num, 228 int version, char *meta_path) 229 { 230 snprintf(meta_path, REE_FS_NAME_MAX, "%s/block%zu.%d", 231 file, block_num, version); 232 } 233 234 static int create_block_file(struct tee_fs_fd *fdp, 235 struct tee_fs_file_meta *new_meta, int block_num) 236 { 237 int fd; 238 int res = -1; 239 char block_path[REE_FS_NAME_MAX]; 240 uint8_t new_version = 241 !get_backup_version_of_block(fdp->meta, block_num); 242 243 get_block_filepath(fdp->filename, block_num, new_version, 244 block_path); 245 246 fd = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, block_path, 247 TEE_FS_O_CREATE | TEE_FS_O_RDWR); 248 if (fd < 0) 249 goto exit; 250 251 res = tee_fs_rpc_ftruncate(OPTEE_MSG_RPC_CMD_FS, fd, 0); 252 if (res < 0) 253 goto exit; 254 255 /* 256 * toggle block version in new meta to indicate 257 * we are currently working on new block file 258 */ 259 toggle_backup_version_of_block(new_meta, block_num); 260 res = fd; 261 262 exit: 263 return res; 264 } 265 266 static int __remove_block_file(struct tee_fs_fd *fdp, size_t block_num, 267 bool toggle) 268 { 269 char block_path[REE_FS_NAME_MAX]; 270 uint8_t version = 271 get_backup_version_of_block(fdp->meta, block_num); 272 273 if (toggle) 274 version = !version; 275 276 get_block_filepath(fdp->filename, block_num, version, block_path); 277 DMSG("%s", block_path); 278 279 /* ignore it if file not found */ 280 if (ree_fs_access_rpc(block_path, TEE_FS_F_OK)) 281 return 0; 282 283 return tee_fs_rpc_unlink(OPTEE_MSG_RPC_CMD_FS, block_path); 284 } 285 286 static int remove_block_file(struct tee_fs_fd *fdp, size_t block_num) 287 { 288 DMSG("remove block%zd", block_num); 289 return __remove_block_file(fdp, block_num, false); 290 } 291 292 static int remove_outdated_block(struct tee_fs_fd *fdp, size_t block_num) 293 { 294 DMSG("remove outdated block%zd", block_num); 295 return __remove_block_file(fdp, block_num, true); 296 } 297 298 /* 299 * encrypted_fek: as input for META_FILE and BLOCK_FILE 300 */ 301 static int encrypt_and_write_file(int fd, 302 enum tee_fs_file_type file_type, 303 void *data_in, size_t data_in_size, 304 uint8_t *encrypted_fek) 305 { 306 TEE_Result tee_res; 307 int res = 0; 308 int bytes; 309 uint8_t *ciphertext; 310 size_t header_size = tee_fs_get_header_size(file_type); 311 size_t ciphertext_size = header_size + data_in_size; 312 313 ciphertext = malloc(ciphertext_size); 314 if (!ciphertext) { 315 EMSG("Failed to allocate ciphertext buffer, size=%zd", 316 ciphertext_size); 317 return -1; 318 } 319 320 tee_res = tee_fs_encrypt_file(file_type, 321 data_in, data_in_size, 322 ciphertext, &ciphertext_size, encrypted_fek); 323 if (tee_res != TEE_SUCCESS) { 324 EMSG("error code=%x", tee_res); 325 res = -1; 326 goto fail; 327 } 328 329 bytes = tee_fs_rpc_write(OPTEE_MSG_RPC_CMD_FS, fd, ciphertext, 330 ciphertext_size); 331 if (bytes != (int)ciphertext_size) { 332 EMSG("bytes(%d) != ciphertext size(%zu)", 333 bytes, ciphertext_size); 334 res = -1; 335 goto fail; 336 } 337 338 fail: 339 free(ciphertext); 340 341 return res; 342 } 343 344 /* 345 * encrypted_fek: as output for META_FILE 346 * as input for BLOCK_FILE 347 */ 348 static int read_and_decrypt_file(int fd, 349 enum tee_fs_file_type file_type, 350 void *data_out, size_t *data_out_size, 351 uint8_t *encrypted_fek) 352 { 353 TEE_Result tee_res; 354 int res; 355 int bytes; 356 void *ciphertext = NULL; 357 size_t file_size; 358 size_t header_size = tee_fs_get_header_size(file_type); 359 360 res = get_file_length(fd, &file_size); 361 if (res < 0) 362 return res; 363 364 if (file_size < header_size) 365 panic("file too short"); 366 367 ciphertext = malloc(file_size); 368 if (!ciphertext) { 369 EMSG("Failed to allocate file data buffer, size=%zd", 370 file_size); 371 return -1; 372 } 373 374 bytes = tee_fs_rpc_read(OPTEE_MSG_RPC_CMD_FS, fd, ciphertext, 375 file_size); 376 if (bytes != (int)file_size) { 377 EMSG("return bytes(%d) != file_size(%zd)", 378 bytes, file_size); 379 res = -1; 380 goto fail; 381 } 382 383 tee_res = tee_fs_decrypt_file(file_type, 384 ciphertext, file_size, 385 data_out, data_out_size, 386 encrypted_fek); 387 if (tee_res != TEE_SUCCESS) { 388 EMSG("Failed to decrypt file, res=0x%x", tee_res); 389 res = -1; 390 } 391 392 fail: 393 free(ciphertext); 394 395 return (res < 0) ? res : 0; 396 } 397 398 static struct tee_fs_file_meta *duplicate_meta( 399 struct tee_fs_fd *fdp) 400 { 401 struct tee_fs_file_meta *new_meta = NULL; 402 403 new_meta = malloc(sizeof(*new_meta)); 404 if (!new_meta) { 405 EMSG("Failed to allocate memory for new meta"); 406 goto exit; 407 } 408 409 memcpy(new_meta, fdp->meta, sizeof(*new_meta)); 410 411 exit: 412 return new_meta; 413 } 414 415 static int write_meta_file(const char *filename, 416 struct tee_fs_file_meta *meta) 417 { 418 int res, fd = -1; 419 char meta_path[REE_FS_NAME_MAX]; 420 421 get_meta_filepath(filename, meta->backup_version, meta_path); 422 423 fd = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, meta_path, TEE_FS_O_CREATE | 424 TEE_FS_O_TRUNC | TEE_FS_O_WRONLY); 425 if (fd < 0) 426 return -1; 427 428 res = encrypt_and_write_file(fd, META_FILE, 429 (void *)&meta->info, sizeof(meta->info), 430 meta->encrypted_fek); 431 432 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fd); 433 return res; 434 } 435 436 static struct tee_fs_file_meta *create_meta_file(const char *file) 437 { 438 TEE_Result tee_res; 439 struct tee_fs_file_meta *meta = NULL; 440 int res; 441 const uint8_t default_backup_version = 0; 442 443 meta = malloc(sizeof(struct tee_fs_file_meta)); 444 if (!meta) { 445 EMSG("Failed to allocate memory"); 446 goto exit; 447 } 448 449 memset(&meta->info.backup_version_table, 0xff, 450 sizeof(meta->info.backup_version_table)); 451 meta->info.length = 0; 452 453 tee_res = tee_fs_generate_fek(meta->encrypted_fek, TEE_FS_KM_FEK_SIZE); 454 if (tee_res != TEE_SUCCESS) 455 goto exit; 456 457 meta->backup_version = default_backup_version; 458 459 res = write_meta_file(file, meta); 460 if (res < 0) 461 goto exit; 462 463 return meta; 464 465 exit: 466 free(meta); 467 468 return NULL; 469 } 470 471 static int commit_meta_file(struct tee_fs_fd *fdp, 472 struct tee_fs_file_meta *new_meta) 473 { 474 int res; 475 uint8_t old_version; 476 char meta_path[REE_FS_NAME_MAX]; 477 478 old_version = new_meta->backup_version; 479 new_meta->backup_version = !new_meta->backup_version; 480 481 res = write_meta_file(fdp->filename, new_meta); 482 483 if (res < 0) 484 return res; 485 486 /* 487 * From now on the new meta is successfully committed, 488 * change tee_fs_fd accordingly 489 */ 490 memcpy(fdp->meta, new_meta, sizeof(*new_meta)); 491 492 /* 493 * Remove outdated meta file, there is nothing we can 494 * do if we fail here, but that is OK because both 495 * new & old version of block files are kept. The context 496 * of the file is still consistent. 497 */ 498 get_meta_filepath(fdp->filename, old_version, meta_path); 499 tee_fs_rpc_unlink(OPTEE_MSG_RPC_CMD_FS, meta_path); 500 501 return res; 502 } 503 504 static int read_meta_file(const char *meta_path, 505 struct tee_fs_file_meta *meta) 506 { 507 int res, fd; 508 size_t meta_info_size = sizeof(struct tee_fs_file_info); 509 510 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, meta_path, TEE_FS_O_RDWR); 511 if (res < 0) 512 return res; 513 514 fd = res; 515 516 res = read_and_decrypt_file(fd, META_FILE, 517 (void *)&meta->info, &meta_info_size, 518 meta->encrypted_fek); 519 520 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fd); 521 522 return res; 523 } 524 525 static struct tee_fs_file_meta *open_meta_file( 526 const char *file, int version) 527 { 528 int res; 529 char meta_path[REE_FS_NAME_MAX]; 530 struct tee_fs_file_meta *meta = NULL; 531 532 meta = malloc(sizeof(struct tee_fs_file_meta)); 533 if (!meta) 534 return NULL; 535 536 get_meta_filepath(file, version, meta_path); 537 res = read_meta_file(meta_path, meta); 538 if (res < 0) 539 goto exit_free_meta; 540 541 meta->backup_version = version; 542 543 return meta; 544 545 exit_free_meta: 546 free(meta); 547 return NULL; 548 } 549 550 static bool is_block_file_exist(struct tee_fs_file_meta *meta, 551 size_t block_num) 552 { 553 size_t file_size = meta->info.length; 554 555 if (file_size == 0) 556 return false; 557 558 return (block_num <= (size_t)get_last_block_num(file_size)); 559 } 560 561 static int read_block_from_storage(struct tee_fs_fd *fdp, struct block *b) 562 { 563 int fd, res = 0; 564 uint8_t *plaintext = b->data; 565 char block_path[REE_FS_NAME_MAX]; 566 size_t block_file_size = BLOCK_FILE_SIZE; 567 uint8_t version = get_backup_version_of_block(fdp->meta, 568 b->block_num); 569 570 if (!is_block_file_exist(fdp->meta, b->block_num)) 571 goto exit; 572 573 get_block_filepath(fdp->filename, b->block_num, version, 574 block_path); 575 576 fd = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, block_path, 577 TEE_FS_O_RDONLY); 578 if (fd < 0) 579 return fd; 580 581 res = read_and_decrypt_file(fd, BLOCK_FILE, 582 plaintext, &block_file_size, 583 fdp->meta->encrypted_fek); 584 if (res < 0) { 585 EMSG("Failed to read and decrypt file"); 586 goto fail; 587 } 588 b->data_size = block_file_size; 589 DMSG("Successfully read and decrypt block%d from storage, size=%zd", 590 b->block_num, b->data_size); 591 fail: 592 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fd); 593 exit: 594 return res; 595 } 596 597 static int flush_block_to_storage(struct tee_fs_fd *fdp, struct block *b, 598 struct tee_fs_file_meta *new_meta) 599 { 600 int fd = -1; 601 int res; 602 size_t block_num = b->block_num; 603 604 fd = create_block_file( 605 fdp, new_meta, block_num); 606 if (fd < 0) { 607 EMSG("Failed to create new version of block"); 608 res = -1; 609 goto fail; 610 } 611 612 res = encrypt_and_write_file(fd, BLOCK_FILE, 613 b->data, b->data_size, 614 new_meta->encrypted_fek); 615 if (res < 0) { 616 EMSG("Failed to encrypt and write block file"); 617 goto fail; 618 } 619 DMSG("Successfully encrypt and write block%d to storage, size=%zd", 620 b->block_num, b->data_size); 621 622 fail: 623 if (fd > 0) 624 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fd); 625 626 return res; 627 } 628 629 static struct block *alloc_block(void) 630 { 631 struct block *c; 632 633 c = malloc(sizeof(struct block)); 634 if (!c) 635 return NULL; 636 637 c->data = malloc(BLOCK_FILE_SIZE); 638 if (!c->data) { 639 EMSG("unable to alloc memory for block data"); 640 goto exit; 641 } 642 643 c->block_num = -1; 644 c->data_size = 0; 645 646 return c; 647 648 exit: 649 free(c); 650 return NULL; 651 } 652 653 #ifdef CFG_FS_BLOCK_CACHE 654 static void free_block(struct block *b) 655 { 656 if (b) { 657 free(b->data); 658 free(b); 659 } 660 } 661 662 static inline bool is_block_data_invalid(struct block *b) 663 { 664 return (b->data_size == 0); 665 } 666 667 static void get_block_from_cache(struct block_cache *cache, 668 int block_num, struct block **out_block) 669 { 670 struct block *b, *found = NULL; 671 672 DMSG("Try to find block%d in cache", block_num); 673 TAILQ_FOREACH(b, &cache->block_lru, list) { 674 if (b->block_num == block_num) { 675 DMSG("Found in cache"); 676 found = b; 677 break; 678 } 679 } 680 681 if (found) { 682 TAILQ_REMOVE(&cache->block_lru, found, list); 683 TAILQ_INSERT_HEAD(&cache->block_lru, found, list); 684 *out_block = found; 685 return; 686 } 687 688 DMSG("Not found, reuse oldest block on LRU list"); 689 b = TAILQ_LAST(&cache->block_lru, block_head); 690 TAILQ_REMOVE(&cache->block_lru, b, list); 691 TAILQ_INSERT_HEAD(&cache->block_lru, b, list); 692 b->block_num = block_num; 693 b->data_size = 0; 694 *out_block = b; 695 } 696 697 static int init_block_cache(struct block_cache *cache) 698 { 699 struct block *b; 700 701 TAILQ_INIT(&cache->block_lru); 702 cache->cached_block_num = 0; 703 704 while (cache->cached_block_num < MAX_NUM_CACHED_BLOCKS) { 705 706 b = alloc_block(); 707 if (!b) { 708 EMSG("Failed to alloc block"); 709 goto fail; 710 } else { 711 TAILQ_INSERT_HEAD(&cache->block_lru, b, list); 712 cache->cached_block_num++; 713 } 714 } 715 return 0; 716 717 fail: 718 TAILQ_FOREACH(b, &cache->block_lru, list) 719 free_block(b); 720 return -1; 721 } 722 723 static void destroy_block_cache(struct block_cache *cache) 724 { 725 struct block *b, *next; 726 727 TAILQ_FOREACH_SAFE(b, &cache->block_lru, list, next) { 728 TAILQ_REMOVE(&cache->block_lru, b, list); 729 free_block(b); 730 } 731 } 732 #else 733 static int init_block_cache(struct block_cache *cache __unused) 734 { 735 return 0; 736 } 737 738 static void destroy_block_cache(struct block_cache *cache __unused) 739 { 740 } 741 #endif 742 743 static void write_data_to_block(struct block *b, int offset, 744 void *buf, size_t len) 745 { 746 DMSG("Write %zd bytes to block%d", len, b->block_num); 747 memcpy(b->data + offset, buf, len); 748 if (offset + len > b->data_size) { 749 b->data_size = offset + len; 750 DMSG("Extend block%d size to %zd bytes", 751 b->block_num, b->data_size); 752 } 753 } 754 755 static void read_data_from_block(struct block *b, int offset, 756 void *buf, size_t len) 757 { 758 DMSG("Read %zd bytes from block%d", len, b->block_num); 759 if (offset + len > b->data_size) 760 panic("Exceeding block size"); 761 memcpy(buf, b->data + offset, len); 762 } 763 764 #ifdef CFG_FS_BLOCK_CACHE 765 static struct block *read_block_with_cache(struct tee_fs_fd *fdp, int block_num) 766 { 767 struct block *b; 768 769 get_block_from_cache(&fdp->block_cache, block_num, &b); 770 if (is_block_data_invalid(b)) 771 if (read_block_from_storage(fdp, b)) { 772 EMSG("Unable to read block%d from storage", 773 block_num); 774 return NULL; 775 } 776 777 return b; 778 } 779 #else 780 781 static struct block *read_block_no_cache(struct tee_fs_fd *fdp, int block_num) 782 { 783 static struct block *b; 784 int res; 785 786 if (!b) 787 b = alloc_block(); 788 b->block_num = block_num; 789 790 res = read_block_from_storage(fdp, b); 791 if (res) 792 EMSG("Unable to read block%d from storage", 793 block_num); 794 795 return res ? NULL : b; 796 } 797 #endif 798 799 static struct block_operations block_ops = { 800 #ifdef CFG_FS_BLOCK_CACHE 801 .read = read_block_with_cache, 802 #else 803 .read = read_block_no_cache, 804 #endif 805 .write = flush_block_to_storage, 806 }; 807 808 static int out_of_place_write(struct tee_fs_fd *fdp, const void *buf, 809 size_t len, struct tee_fs_file_meta *new_meta) 810 { 811 int start_block_num = pos_to_block_num(fdp->pos); 812 int end_block_num = pos_to_block_num(fdp->pos + len - 1); 813 size_t remain_bytes = len; 814 uint8_t *data_ptr = (uint8_t *)buf; 815 int orig_pos = fdp->pos; 816 817 while (start_block_num <= end_block_num) { 818 int offset = fdp->pos % BLOCK_FILE_SIZE; 819 struct block *b; 820 size_t size_to_write = (remain_bytes > BLOCK_FILE_SIZE) ? 821 BLOCK_FILE_SIZE : remain_bytes; 822 823 if (size_to_write + offset > BLOCK_FILE_SIZE) 824 size_to_write = BLOCK_FILE_SIZE - offset; 825 826 b = block_ops.read(fdp, start_block_num); 827 if (!b) 828 goto failed; 829 830 DMSG("Write data, offset: %d, size_to_write: %zd", 831 offset, size_to_write); 832 write_data_to_block(b, offset, data_ptr, size_to_write); 833 834 if (block_ops.write(fdp, b, new_meta)) { 835 EMSG("Unable to wrtie block%d to storage", 836 b->block_num); 837 goto failed; 838 } 839 840 data_ptr += size_to_write; 841 remain_bytes -= size_to_write; 842 start_block_num++; 843 fdp->pos += size_to_write; 844 } 845 846 if (fdp->pos > (tee_fs_off_t)new_meta->info.length) 847 new_meta->info.length = fdp->pos; 848 849 return 0; 850 failed: 851 fdp->pos = orig_pos; 852 return -1; 853 } 854 855 static inline int create_hard_link(const char *old_dir, 856 const char *new_dir, 857 const char *filename) 858 { 859 char old_path[REE_FS_NAME_MAX]; 860 char new_path[REE_FS_NAME_MAX]; 861 862 snprintf(old_path, REE_FS_NAME_MAX, "%s/%s", 863 old_dir, filename); 864 snprintf(new_path, REE_FS_NAME_MAX, "%s/%s", 865 new_dir, filename); 866 867 DMSG("%s -> %s", old_path, new_path); 868 return tee_fs_rpc_link(OPTEE_MSG_RPC_CMD_FS, old_path, new_path); 869 } 870 871 static int unlink_tee_file(const char *file) 872 { 873 int res = -1; 874 size_t len = strlen(file) + 1; 875 struct tee_fs_dirent *dirent; 876 struct tee_fs_dir *dir; 877 878 DMSG("file=%s", file); 879 880 if (len > TEE_FS_NAME_MAX) 881 goto exit; 882 883 dir = ree_fs_opendir_rpc(file); 884 if (!dir) 885 goto exit; 886 887 dirent = ree_fs_readdir_rpc(dir); 888 while (dirent) { 889 char path[REE_FS_NAME_MAX]; 890 891 snprintf(path, REE_FS_NAME_MAX, "%s/%s", 892 file, dirent->d_name); 893 894 DMSG("unlink %s", path); 895 res = tee_fs_rpc_unlink(OPTEE_MSG_RPC_CMD_FS, path); 896 if (res) { 897 ree_fs_closedir_rpc(dir); 898 goto exit; 899 } 900 901 dirent = ree_fs_readdir_rpc(dir); 902 } 903 904 res = ree_fs_closedir_rpc(dir); 905 if (res) 906 goto exit; 907 908 res = ree_fs_rmdir_rpc(file); 909 exit: 910 return res; 911 } 912 913 static bool tee_file_exists(const char *file) 914 { 915 char meta_path[REE_FS_NAME_MAX]; 916 917 get_meta_filepath(file, 0, meta_path); 918 if (ree_fs_access_rpc(meta_path, TEE_FS_F_OK)) { 919 get_meta_filepath(file, 1, meta_path); 920 if (ree_fs_access_rpc(meta_path, TEE_FS_F_OK)) 921 return false; 922 } 923 924 return true; 925 } 926 927 static struct tee_fs_file_meta *create_tee_file(const char *file) 928 { 929 struct tee_fs_file_meta *meta = NULL; 930 int res; 931 932 DMSG("Creating TEE file=%s", file); 933 934 /* create TEE file directory if not exist */ 935 if (ree_fs_access_rpc(file, TEE_FS_F_OK)) { 936 res = ree_fs_mkdir_rpc(file, 937 TEE_FS_S_IRUSR | TEE_FS_S_IWUSR | TEE_FS_S_IXUSR); 938 if (res) { 939 EMSG("Failed to create TEE file directory, res=%d", 940 res); 941 goto exit; 942 } 943 } 944 945 /* create meta file in TEE file directory */ 946 meta = create_meta_file(file); 947 if (!meta) 948 EMSG("Failed to create new meta file"); 949 950 exit: 951 return meta; 952 } 953 954 static struct tee_fs_file_meta *open_tee_file(const char *file) 955 { 956 struct tee_fs_file_meta *meta = NULL; 957 int backup_version = 0; 958 959 DMSG("Opening TEE file=%s", file); 960 961 meta = open_meta_file(file, backup_version); 962 if (!meta) { 963 meta = open_meta_file(file, !backup_version); 964 if (!meta) { 965 /* 966 * cannot open meta file, assumed the TEE file 967 * is corrupted 968 */ 969 EMSG("Can not open meta file"); 970 } 971 } 972 973 return meta; 974 } 975 976 static int ree_fs_ftruncate_internal(TEE_Result *errno, struct tee_fs_fd *fdp, 977 tee_fs_off_t new_file_len); 978 979 static int ree_fs_open(TEE_Result *errno, const char *file, int flags, ...) 980 { 981 int res = -1; 982 size_t len; 983 struct tee_fs_file_meta *meta = NULL; 984 struct tee_fs_fd *fdp = NULL; 985 bool file_exist; 986 987 mutex_lock(&ree_fs_mutex); 988 989 assert(errno); 990 *errno = TEE_SUCCESS; 991 992 if (!file) { 993 *errno = TEE_ERROR_BAD_PARAMETERS; 994 goto exit; 995 } 996 997 len = strlen(file) + 1; 998 if (len > TEE_FS_NAME_MAX) { 999 *errno = TEE_ERROR_BAD_PARAMETERS; 1000 goto exit; 1001 } 1002 1003 file_exist = tee_file_exists(file); 1004 if (flags & TEE_FS_O_CREATE) { 1005 if ((flags & TEE_FS_O_EXCL) && file_exist) { 1006 DMSG("tee file already exists"); 1007 *errno = TEE_ERROR_ACCESS_CONFLICT; 1008 goto exit; 1009 } 1010 1011 if (!file_exist) 1012 meta = create_tee_file(file); 1013 else 1014 meta = open_tee_file(file); 1015 1016 } else { 1017 if (!file_exist) { 1018 DMSG("tee file not exists"); 1019 *errno = TEE_ERROR_ITEM_NOT_FOUND; 1020 goto exit; 1021 } 1022 1023 meta = open_tee_file(file); 1024 } 1025 1026 if (!meta) { 1027 EMSG("Failed to open TEE file"); 1028 *errno = TEE_ERROR_CORRUPT_OBJECT; 1029 goto exit; 1030 } 1031 1032 DMSG("file=%s, length=%zd", file, meta->info.length); 1033 fdp = (struct tee_fs_fd *)malloc(sizeof(struct tee_fs_fd)); 1034 if (!fdp) { 1035 *errno = TEE_ERROR_OUT_OF_MEMORY; 1036 goto exit_free_meta; 1037 } 1038 1039 /* init internal status */ 1040 fdp->flags = flags; 1041 fdp->meta = meta; 1042 fdp->pos = 0; 1043 if (init_block_cache(&fdp->block_cache)) { 1044 res = -1; 1045 goto exit_free_fd; 1046 } 1047 1048 fdp->filename = malloc(len); 1049 if (!fdp->filename) { 1050 res = -1; 1051 *errno = TEE_ERROR_OUT_OF_MEMORY; 1052 goto exit_destroy_block_cache; 1053 } 1054 memcpy(fdp->filename, file, len); 1055 1056 if ((flags & TEE_FS_O_TRUNC) && 1057 (flags & TEE_FS_O_WRONLY || flags & TEE_FS_O_RDWR)) { 1058 res = ree_fs_ftruncate_internal(errno, fdp, 0); 1059 if (res < 0) { 1060 EMSG("Unable to truncate file"); 1061 goto exit_free_filename; 1062 } 1063 } 1064 1065 /* return fd */ 1066 res = handle_get(&fs_handle_db, fdp); 1067 if (res < 0) 1068 goto exit_free_filename; 1069 fdp->fd = res; 1070 goto exit; 1071 1072 exit_free_filename: 1073 free(fdp->filename); 1074 exit_destroy_block_cache: 1075 destroy_block_cache(&fdp->block_cache); 1076 exit_free_fd: 1077 free(fdp); 1078 exit_free_meta: 1079 free(meta); 1080 exit: 1081 mutex_unlock(&ree_fs_mutex); 1082 return res; 1083 } 1084 1085 static int ree_fs_close(int fd) 1086 { 1087 int res = -1; 1088 struct tee_fs_fd *fdp; 1089 1090 mutex_lock(&ree_fs_mutex); 1091 1092 fdp = handle_lookup(&fs_handle_db, fd); 1093 if (!fdp) 1094 goto exit; 1095 1096 handle_put(&fs_handle_db, fdp->fd); 1097 1098 destroy_block_cache(&fdp->block_cache); 1099 free(fdp->meta); 1100 free(fdp->filename); 1101 free(fdp); 1102 1103 exit: 1104 mutex_unlock(&ree_fs_mutex); 1105 return res; 1106 } 1107 1108 static tee_fs_off_t ree_fs_lseek(TEE_Result *errno, int fd, 1109 tee_fs_off_t offset, int whence) 1110 { 1111 tee_fs_off_t res = -1; 1112 tee_fs_off_t new_pos; 1113 size_t filelen; 1114 struct tee_fs_fd *fdp; 1115 1116 mutex_lock(&ree_fs_mutex); 1117 1118 assert(errno); 1119 *errno = TEE_SUCCESS; 1120 1121 fdp = handle_lookup(&fs_handle_db, fd); 1122 if (!fdp) { 1123 *errno = TEE_ERROR_BAD_PARAMETERS; 1124 goto exit; 1125 } 1126 1127 DMSG("offset=%d, whence=%d", (int)offset, whence); 1128 1129 filelen = fdp->meta->info.length; 1130 1131 switch (whence) { 1132 case TEE_FS_SEEK_SET: 1133 new_pos = offset; 1134 break; 1135 1136 case TEE_FS_SEEK_CUR: 1137 new_pos = fdp->pos + offset; 1138 break; 1139 1140 case TEE_FS_SEEK_END: 1141 new_pos = filelen + offset; 1142 break; 1143 1144 default: 1145 *errno = TEE_ERROR_BAD_PARAMETERS; 1146 goto exit; 1147 } 1148 1149 if (new_pos < 0) 1150 new_pos = 0; 1151 1152 if (new_pos > TEE_DATA_MAX_POSITION) { 1153 EMSG("Position is beyond TEE_DATA_MAX_POSITION"); 1154 *errno = TEE_ERROR_BAD_PARAMETERS; 1155 goto exit; 1156 } 1157 1158 res = fdp->pos = new_pos; 1159 exit: 1160 mutex_unlock(&ree_fs_mutex); 1161 return res; 1162 } 1163 1164 /* 1165 * To ensure atomic truncate operation, we can: 1166 * 1167 * - update file length to new length 1168 * - commit new meta 1169 * - free unused blocks 1170 * 1171 * To ensure atomic extend operation, we can: 1172 * 1173 * - update file length to new length 1174 * - allocate and fill zero data to new blocks 1175 * - commit new meta 1176 * 1177 * Any failure before committing new meta is considered as 1178 * update failed, and the file content will not be updated 1179 */ 1180 static int ree_fs_ftruncate_internal(TEE_Result *errno, struct tee_fs_fd *fdp, 1181 tee_fs_off_t new_file_len) 1182 { 1183 int res = -1; 1184 size_t old_file_len = fdp->meta->info.length; 1185 struct tee_fs_file_meta *new_meta = NULL; 1186 uint8_t *buf = NULL; 1187 1188 assert(errno); 1189 *errno = TEE_SUCCESS; 1190 1191 if (!fdp) { 1192 *errno = TEE_ERROR_BAD_PARAMETERS; 1193 res = -1; 1194 goto exit; 1195 } 1196 1197 if (fdp->flags & TEE_FS_O_RDONLY) { 1198 *errno = TEE_ERROR_BAD_PARAMETERS; 1199 EMSG("Read only"); 1200 res = -1; 1201 goto exit; 1202 } 1203 1204 if ((size_t)new_file_len == old_file_len) { 1205 DMSG("Ignore due to file length does not changed"); 1206 res = 0; 1207 goto exit; 1208 } 1209 1210 if (new_file_len > MAX_FILE_SIZE) { 1211 *errno = TEE_ERROR_BAD_PARAMETERS; 1212 EMSG("Over maximum file size(%d)", MAX_FILE_SIZE); 1213 res = -1; 1214 goto exit; 1215 } 1216 1217 new_meta = duplicate_meta(fdp); 1218 if (!new_meta) { 1219 *errno = TEE_ERROR_OUT_OF_MEMORY; 1220 res = -1; 1221 goto free; 1222 } 1223 1224 new_meta->info.length = new_file_len; 1225 1226 if ((size_t)new_file_len < old_file_len) { 1227 int old_block_num = get_last_block_num(old_file_len); 1228 int new_block_num = get_last_block_num(new_file_len); 1229 1230 DMSG("Truncate file length to %zu", (size_t)new_file_len); 1231 1232 res = commit_meta_file(fdp, new_meta); 1233 if (res < 0) { 1234 *errno = TEE_ERROR_CORRUPT_OBJECT; 1235 EMSG("Failed to commit meta file"); 1236 goto free; 1237 } 1238 1239 /* now we are safe to free unused blocks */ 1240 while (old_block_num > new_block_num) { 1241 if (remove_block_file(fdp, old_block_num)) { 1242 IMSG("Warning: Failed to free block: %d", 1243 old_block_num); 1244 } 1245 1246 old_block_num--; 1247 } 1248 1249 } else { 1250 size_t ext_len = new_file_len - old_file_len; 1251 int orig_pos = fdp->pos; 1252 1253 buf = malloc(BLOCK_FILE_SIZE); 1254 if (!buf) { 1255 *errno = TEE_ERROR_OUT_OF_MEMORY; 1256 EMSG("Failed to allocate buffer, size=%d", 1257 BLOCK_FILE_SIZE); 1258 res = -1; 1259 goto free; 1260 } 1261 1262 memset(buf, 0x0, BLOCK_FILE_SIZE); 1263 1264 DMSG("Extend file length to %zu", (size_t)new_file_len); 1265 1266 fdp->pos = old_file_len; 1267 1268 res = 0; 1269 while (ext_len > 0) { 1270 size_t data_len = (ext_len > BLOCK_FILE_SIZE) ? 1271 BLOCK_FILE_SIZE : ext_len; 1272 1273 DMSG("fill len=%zu", data_len); 1274 res = out_of_place_write(fdp, (void *)buf, 1275 data_len, new_meta); 1276 if (res < 0) { 1277 *errno = TEE_ERROR_CORRUPT_OBJECT; 1278 EMSG("Failed to fill data"); 1279 break; 1280 } 1281 1282 ext_len -= data_len; 1283 } 1284 1285 fdp->pos = orig_pos; 1286 1287 if (res == 0) { 1288 res = commit_meta_file(fdp, new_meta); 1289 if (res < 0) { 1290 *errno = TEE_ERROR_CORRUPT_OBJECT; 1291 EMSG("Failed to commit meta file"); 1292 } 1293 } 1294 } 1295 1296 free: 1297 free(new_meta); 1298 free(buf); 1299 1300 exit: 1301 return res; 1302 } 1303 1304 static int ree_fs_read(TEE_Result *errno, int fd, void *buf, size_t len) 1305 { 1306 int res = -1; 1307 int start_block_num; 1308 int end_block_num; 1309 size_t remain_bytes = len; 1310 uint8_t *data_ptr = buf; 1311 struct tee_fs_fd *fdp; 1312 1313 mutex_lock(&ree_fs_mutex); 1314 1315 assert(errno); 1316 *errno = TEE_SUCCESS; 1317 1318 fdp = handle_lookup(&fs_handle_db, fd); 1319 if (!fdp) { 1320 *errno = TEE_ERROR_BAD_PARAMETERS; 1321 goto exit; 1322 } 1323 1324 if ((fdp->pos + len) < len || 1325 fdp->pos > (tee_fs_off_t)fdp->meta->info.length) 1326 len = 0; 1327 else if (fdp->pos + len > fdp->meta->info.length) 1328 len = fdp->meta->info.length - fdp->pos; 1329 1330 if (!len) { 1331 res = 0; 1332 goto exit; 1333 } 1334 1335 if (!buf) { 1336 *errno = TEE_ERROR_BAD_PARAMETERS; 1337 goto exit; 1338 } 1339 1340 if (fdp->flags & TEE_FS_O_WRONLY) { 1341 *errno = TEE_ERROR_ACCESS_CONFLICT; 1342 goto exit; 1343 } 1344 1345 DMSG("%s, data len=%zu", fdp->filename, len); 1346 1347 start_block_num = pos_to_block_num(fdp->pos); 1348 end_block_num = pos_to_block_num(fdp->pos + len - 1); 1349 DMSG("start_block_num:%d, end_block_num:%d", 1350 start_block_num, end_block_num); 1351 1352 while (start_block_num <= end_block_num) { 1353 struct block *b; 1354 int offset = fdp->pos % BLOCK_FILE_SIZE; 1355 size_t size_to_read = remain_bytes > BLOCK_FILE_SIZE ? 1356 BLOCK_FILE_SIZE : remain_bytes; 1357 1358 if (size_to_read + offset > BLOCK_FILE_SIZE) 1359 size_to_read = BLOCK_FILE_SIZE - offset; 1360 1361 DMSG("block_num:%d, offset:%d, size_to_read: %zd", 1362 start_block_num, offset, size_to_read); 1363 1364 b = block_ops.read(fdp, start_block_num); 1365 if (!b) { 1366 *errno = TEE_ERROR_CORRUPT_OBJECT; 1367 goto exit; 1368 } 1369 1370 read_data_from_block(b, offset, data_ptr, size_to_read); 1371 data_ptr += size_to_read; 1372 remain_bytes -= size_to_read; 1373 fdp->pos += size_to_read; 1374 1375 start_block_num++; 1376 } 1377 res = 0; 1378 exit: 1379 mutex_unlock(&ree_fs_mutex); 1380 return (res < 0) ? res : (int)len; 1381 } 1382 1383 /* 1384 * To ensure atomicity of write operation, we need to 1385 * do the following steps: 1386 * (The sequence of operations is very important) 1387 * 1388 * - Create a new backup version of meta file as a copy 1389 * of current meta file. 1390 * - For each blocks to write: 1391 * - Create new backup version for current block. 1392 * - Write data to new backup version. 1393 * - Update the new meta file accordingly. 1394 * - Write the new meta file. 1395 * 1396 * (Any failure in above steps is considered as update failed, 1397 * and the file content will not be updated) 1398 * 1399 * After previous step the update is considered complete, but 1400 * we should do the following clean-up step(s): 1401 * 1402 * - Delete old meta file. 1403 * - Remove old block files. 1404 * 1405 * (Any failure in above steps is considered as a successfully 1406 * update) 1407 */ 1408 static int ree_fs_write(TEE_Result *errno, int fd, const void *buf, size_t len) 1409 { 1410 int res = -1; 1411 struct tee_fs_file_meta *new_meta = NULL; 1412 struct tee_fs_fd *fdp; 1413 size_t file_size; 1414 int orig_pos; 1415 1416 mutex_lock(&ree_fs_mutex); 1417 1418 assert(errno); 1419 *errno = TEE_SUCCESS; 1420 1421 fdp = handle_lookup(&fs_handle_db, fd); 1422 if (!fdp) { 1423 *errno = TEE_ERROR_BAD_PARAMETERS; 1424 goto exit; 1425 } 1426 if (!len) { 1427 res = 0; 1428 goto exit; 1429 } 1430 if (!buf) { 1431 *errno = TEE_ERROR_BAD_PARAMETERS; 1432 goto exit; 1433 } 1434 1435 file_size = fdp->meta->info.length; 1436 orig_pos = fdp->pos; 1437 1438 if (fdp->flags & TEE_FS_O_RDONLY) { 1439 EMSG("Write to a read-only file, denied"); 1440 *errno = TEE_ERROR_ACCESS_CONFLICT; 1441 goto exit; 1442 } 1443 1444 if ((fdp->pos + len) > MAX_FILE_SIZE) { 1445 EMSG("Over maximum file size(%d)", MAX_FILE_SIZE); 1446 *errno = TEE_ERROR_BAD_PARAMETERS; 1447 goto exit; 1448 } 1449 1450 DMSG("%s, data len=%zu", fdp->filename, len); 1451 if (file_size < (size_t)fdp->pos) { 1452 DMSG("File hole detected, try to extend file size"); 1453 res = ree_fs_ftruncate_internal(errno, fdp, fdp->pos); 1454 if (res < 0) 1455 goto exit; 1456 } 1457 1458 new_meta = duplicate_meta(fdp); 1459 if (!new_meta) { 1460 *errno = TEE_ERROR_OUT_OF_MEMORY; 1461 goto exit; 1462 } 1463 1464 res = out_of_place_write(fdp, buf, len, new_meta); 1465 if (res < 0) { 1466 *errno = TEE_ERROR_CORRUPT_OBJECT; 1467 } else { 1468 int r; 1469 int start_block_num; 1470 int end_block_num; 1471 1472 r = commit_meta_file(fdp, new_meta); 1473 if (r < 0) { 1474 *errno = TEE_ERROR_CORRUPT_OBJECT; 1475 res = -1; 1476 } 1477 1478 /* we are safe to free old blocks */ 1479 start_block_num = pos_to_block_num(orig_pos); 1480 end_block_num = pos_to_block_num(fdp->pos - 1); 1481 while (start_block_num <= end_block_num) { 1482 if (remove_outdated_block(fdp, start_block_num)) 1483 IMSG("Warning: Failed to free old block: %d", 1484 start_block_num); 1485 1486 start_block_num++; 1487 } 1488 } 1489 exit: 1490 mutex_unlock(&ree_fs_mutex); 1491 free(new_meta); 1492 return (res < 0) ? res : (int)len; 1493 } 1494 1495 /* 1496 * To ensure atomicity of rename operation, we need to 1497 * do the following steps: 1498 * 1499 * - Create a new folder that represents the renamed TEE file 1500 * - For each REE block files, create a hard link under the just 1501 * created folder (new TEE file) 1502 * - Now we are ready to commit meta, create hard link for the 1503 * meta file 1504 * 1505 * (Any failure in above steps is considered as update failed, 1506 * and the file content will not be updated) 1507 * 1508 * After previous step the update is considered complete, but 1509 * we should do the following clean-up step(s): 1510 * 1511 * - Unlink all REE files represents the old TEE file (including 1512 * meta and block files) 1513 * 1514 * (Any failure in above steps is considered as a successfully 1515 * update) 1516 */ 1517 static int ree_fs_rename_internal(const char *old, const char *new) 1518 { 1519 int res = -1; 1520 size_t old_len; 1521 size_t new_len; 1522 size_t meta_count = 0; 1523 struct tee_fs_dir *old_dir; 1524 struct tee_fs_dirent *dirent; 1525 char *meta_filename = NULL; 1526 1527 if (!old || !new) 1528 return -1; 1529 1530 DMSG("old=%s, new=%s", old, new); 1531 1532 old_len = strlen(old) + 1; 1533 new_len = strlen(new) + 1; 1534 1535 if (old_len > TEE_FS_NAME_MAX || new_len > TEE_FS_NAME_MAX) 1536 goto exit; 1537 1538 res = ree_fs_mkdir_rpc(new, 1539 TEE_FS_S_IRUSR | TEE_FS_S_IWUSR); 1540 if (res) 1541 goto exit; 1542 1543 old_dir = ree_fs_opendir_rpc(old); 1544 if (!old_dir) 1545 goto exit; 1546 1547 dirent = ree_fs_readdir_rpc(old_dir); 1548 while (dirent) { 1549 if (!strncmp(dirent->d_name, "meta.", 5)) { 1550 meta_filename = strdup(dirent->d_name); 1551 meta_count++; 1552 } else { 1553 res = create_hard_link(old, new, dirent->d_name); 1554 if (res) 1555 goto exit_close_old_dir; 1556 } 1557 1558 dirent = ree_fs_readdir_rpc(old_dir); 1559 } 1560 1561 /* finally, link the meta file, rename operation completed */ 1562 if (!meta_filename) 1563 panic("no meta file"); 1564 1565 /* 1566 * TODO: This will cause memory leakage at previous strdup() 1567 * if we accidently have two meta files in a TEE file. 1568 * 1569 * It's not easy to handle the case above (e.g. Which meta file 1570 * should be linked first? What to do if a power cut happened 1571 * during creating links for the two meta files?) 1572 * 1573 * We will solve this issue using another approach: merging 1574 * both meta and block files into a single REE file. This approach 1575 * can completely remove ree_fs_rename(). We can simply 1576 * rename TEE file using REE rename() system call, which is also 1577 * atomic. 1578 */ 1579 if (meta_count > 1) 1580 EMSG("Warning: more than one meta file in your TEE file\n" 1581 "This will cause memory leakage."); 1582 1583 res = create_hard_link(old, new, meta_filename); 1584 if (res) 1585 goto exit_close_old_dir; 1586 1587 /* we are safe now, remove old TEE file */ 1588 unlink_tee_file(old); 1589 1590 exit_close_old_dir: 1591 ree_fs_closedir_rpc(old_dir); 1592 exit: 1593 free(meta_filename); 1594 return res; 1595 } 1596 1597 static int ree_fs_rename(const char *old, const char *new) 1598 { 1599 int res; 1600 1601 mutex_lock(&ree_fs_mutex); 1602 res = ree_fs_rename_internal(old, new); 1603 mutex_unlock(&ree_fs_mutex); 1604 1605 return res; 1606 } 1607 1608 /* 1609 * To ensure atomic unlink operation, we can simply 1610 * split the unlink operation into: 1611 * 1612 * - rename("file", "file.trash"); 1613 * 1614 * (Any failure in above steps is considered as update failed, 1615 * and the file content will not be updated) 1616 * 1617 * After previous step the update is considered complete, but 1618 * we should do the following clean-up step(s): 1619 * 1620 * - unlink("file.trash"); 1621 * 1622 * (Any failure in above steps is considered as a successfully 1623 * update) 1624 */ 1625 static int ree_fs_unlink(const char *file) 1626 { 1627 int res = -1; 1628 char trash_file[TEE_FS_NAME_MAX + 6]; 1629 1630 if (!file) 1631 return -1; 1632 1633 snprintf(trash_file, TEE_FS_NAME_MAX + 6, "%s.trash", 1634 file); 1635 1636 mutex_lock(&ree_fs_mutex); 1637 1638 res = ree_fs_rename_internal(file, trash_file); 1639 if (res < 0) 1640 goto exit; 1641 1642 unlink_tee_file(trash_file); 1643 1644 exit: 1645 mutex_unlock(&ree_fs_mutex); 1646 return res; 1647 } 1648 1649 static int ree_fs_ftruncate(TEE_Result *errno, int fd, tee_fs_off_t length) 1650 { 1651 struct tee_fs_fd *fdp; 1652 int res; 1653 1654 mutex_lock(&ree_fs_mutex); 1655 fdp = handle_lookup(&fs_handle_db, fd); 1656 res = ree_fs_ftruncate_internal(errno, fdp, length); 1657 mutex_unlock(&ree_fs_mutex); 1658 1659 return res; 1660 } 1661 1662 const struct tee_file_operations ree_fs_ops = { 1663 .open = ree_fs_open, 1664 .close = ree_fs_close, 1665 .read = ree_fs_read, 1666 .write = ree_fs_write, 1667 .lseek = ree_fs_lseek, 1668 .ftruncate = ree_fs_ftruncate, 1669 .rename = ree_fs_rename, 1670 .unlink = ree_fs_unlink, 1671 .mkdir = ree_fs_mkdir_rpc, 1672 .opendir = ree_fs_opendir_rpc, 1673 .closedir = ree_fs_closedir_rpc, 1674 .readdir = ree_fs_readdir_rpc, 1675 .rmdir = ree_fs_rmdir_rpc, 1676 .access = ree_fs_access_rpc 1677 }; 1678