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