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 void get_meta_filepath(const char *file, int version, 199 char *meta_path) 200 { 201 snprintf(meta_path, REE_FS_NAME_MAX, "%s/meta.%d", 202 file, version); 203 } 204 205 static void get_block_filepath(const char *file, size_t block_num, 206 int version, char *meta_path) 207 { 208 snprintf(meta_path, REE_FS_NAME_MAX, "%s/block%zu.%d", 209 file, block_num, version); 210 } 211 212 static int __remove_block_file(struct tee_fs_fd *fdp, size_t block_num, 213 bool toggle) 214 { 215 TEE_Result res; 216 char block_path[REE_FS_NAME_MAX]; 217 uint8_t version = get_backup_version_of_block(&fdp->meta, block_num); 218 219 if (toggle) 220 version = !version; 221 222 get_block_filepath(fdp->filename, block_num, version, block_path); 223 DMSG("%s", block_path); 224 225 res = tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, block_path); 226 if (res == TEE_SUCCESS || res == TEE_ERROR_ITEM_NOT_FOUND) 227 return 0; /* ignore it if file not found */ 228 return -1; 229 } 230 231 static int remove_block_file(struct tee_fs_fd *fdp, size_t block_num) 232 { 233 DMSG("remove block%zd", block_num); 234 return __remove_block_file(fdp, block_num, false); 235 } 236 237 static int remove_outdated_block(struct tee_fs_fd *fdp, size_t block_num) 238 { 239 DMSG("remove outdated block%zd", block_num); 240 return __remove_block_file(fdp, block_num, true); 241 } 242 243 /* 244 * encrypted_fek: as input for META_FILE and BLOCK_FILE 245 */ 246 static TEE_Result encrypt_and_write_file(const char *file_name, 247 enum tee_fs_file_type file_type, 248 void *data_in, size_t data_in_size, 249 uint8_t *encrypted_fek) 250 { 251 TEE_Result res; 252 TEE_Result res2; 253 struct tee_fs_rpc_operation op; 254 void *ciphertext; 255 size_t header_size = tee_fs_get_header_size(file_type); 256 size_t ciphertext_size = header_size + data_in_size; 257 int fd; 258 259 res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, file_name, &fd); 260 if (res != TEE_SUCCESS) { 261 if (res != TEE_ERROR_ITEM_NOT_FOUND) 262 return res; 263 res = tee_fs_rpc_new_create(OPTEE_MSG_RPC_CMD_FS, file_name, 264 &fd); 265 if (res != TEE_SUCCESS) 266 return res; 267 } 268 269 res = tee_fs_rpc_new_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fd, 0, 270 ciphertext_size, &ciphertext); 271 if (res != TEE_SUCCESS) 272 goto out; 273 274 res = tee_fs_encrypt_file(file_type, data_in, data_in_size, 275 ciphertext, &ciphertext_size, encrypted_fek); 276 if (res != TEE_SUCCESS) 277 goto out; 278 279 res = tee_fs_rpc_new_write_final(&op); 280 out: 281 res2 = tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fd); 282 if (res == TEE_SUCCESS) 283 return res2; 284 return res; 285 } 286 287 /* 288 * encrypted_fek: as output for META_FILE 289 * as input for BLOCK_FILE 290 */ 291 static TEE_Result read_and_decrypt_file(const char *file_name, 292 enum tee_fs_file_type file_type, 293 void *data_out, size_t *data_out_size, 294 uint8_t *encrypted_fek) 295 { 296 TEE_Result res; 297 TEE_Result res2; 298 struct tee_fs_rpc_operation op; 299 size_t bytes; 300 void *ciphertext; 301 int fd; 302 303 res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, file_name, &fd); 304 if (res != TEE_SUCCESS) 305 return res; 306 307 bytes = *data_out_size + tee_fs_get_header_size(file_type); 308 res = tee_fs_rpc_new_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fd, 0, 309 bytes, &ciphertext); 310 if (res != TEE_SUCCESS) 311 goto out; 312 313 res = tee_fs_rpc_new_read_final(&op, &bytes); 314 if (res != TEE_SUCCESS) 315 goto out; 316 317 res = tee_fs_decrypt_file(file_type, ciphertext, bytes, data_out, 318 data_out_size, encrypted_fek); 319 if (res != TEE_SUCCESS) 320 res = TEE_ERROR_CORRUPT_OBJECT; 321 out: 322 res2 = tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fd); 323 if (res == TEE_SUCCESS) 324 return res2; 325 return res; 326 } 327 328 static TEE_Result write_meta_file(const char *filename, 329 struct tee_fs_file_meta *meta) 330 { 331 char meta_path[REE_FS_NAME_MAX]; 332 333 get_meta_filepath(filename, meta->backup_version, meta_path); 334 335 return encrypt_and_write_file(meta_path, META_FILE, 336 (void *)&meta->info, sizeof(meta->info), 337 meta->encrypted_fek); 338 339 } 340 341 static TEE_Result create_meta(struct tee_fs_fd *fdp) 342 { 343 TEE_Result res; 344 345 memset(fdp->meta.info.backup_version_table, 0xff, 346 sizeof(fdp->meta.info.backup_version_table)); 347 fdp->meta.info.length = 0; 348 349 res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE); 350 if (res != TEE_SUCCESS) 351 return res; 352 353 fdp->meta.backup_version = 0; 354 355 return write_meta_file(fdp->filename, &fdp->meta); 356 } 357 358 static int commit_meta_file(struct tee_fs_fd *fdp, 359 struct tee_fs_file_meta *new_meta) 360 { 361 int res; 362 uint8_t old_version; 363 char meta_path[REE_FS_NAME_MAX]; 364 365 old_version = new_meta->backup_version; 366 new_meta->backup_version = !new_meta->backup_version; 367 368 res = write_meta_file(fdp->filename, new_meta); 369 370 if (res < 0) 371 return res; 372 373 /* 374 * From now on the new meta is successfully committed, 375 * change tee_fs_fd accordingly 376 */ 377 fdp->meta = *new_meta; 378 379 /* 380 * Remove outdated meta file, there is nothing we can 381 * do if we fail here, but that is OK because both 382 * new & old version of block files are kept. The context 383 * of the file is still consistent. 384 */ 385 get_meta_filepath(fdp->filename, old_version, meta_path); 386 tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, meta_path); 387 388 return res; 389 } 390 391 static TEE_Result read_meta_file(const char *meta_path, 392 struct tee_fs_file_meta *meta) 393 { 394 size_t meta_info_size = sizeof(struct tee_fs_file_info); 395 396 return read_and_decrypt_file(meta_path, META_FILE, 397 &meta->info, &meta_info_size, 398 meta->encrypted_fek); 399 } 400 401 static TEE_Result read_meta(struct tee_fs_fd *fdp) 402 { 403 TEE_Result res; 404 char meta_path[REE_FS_NAME_MAX]; 405 406 get_meta_filepath(fdp->filename, fdp->meta.backup_version, meta_path); 407 res = read_meta_file(meta_path, &fdp->meta); 408 if (res != TEE_SUCCESS) { 409 TEE_Result res2; 410 411 fdp->meta.backup_version = !fdp->meta.backup_version; 412 get_meta_filepath(fdp->filename, fdp->meta.backup_version, 413 meta_path); 414 res2 = read_meta_file(meta_path, &fdp->meta); 415 if (res2 != TEE_ERROR_ITEM_NOT_FOUND) 416 return res2; 417 } 418 419 return res; 420 } 421 422 static bool is_block_file_exist(struct tee_fs_file_meta *meta, 423 size_t block_num) 424 { 425 size_t file_size = meta->info.length; 426 427 if (file_size == 0) 428 return false; 429 430 return (block_num <= (size_t)get_last_block_num(file_size)); 431 } 432 433 static TEE_Result read_block_from_storage(struct tee_fs_fd *fdp, 434 struct block *b) 435 { 436 TEE_Result res = TEE_SUCCESS; 437 uint8_t *plaintext = b->data; 438 char block_path[REE_FS_NAME_MAX]; 439 size_t block_file_size = BLOCK_FILE_SIZE; 440 uint8_t version = get_backup_version_of_block(&fdp->meta, b->block_num); 441 442 if (!is_block_file_exist(&fdp->meta, b->block_num)) 443 goto exit; 444 445 get_block_filepath(fdp->filename, b->block_num, version, 446 block_path); 447 448 res = read_and_decrypt_file(block_path, BLOCK_FILE, 449 plaintext, &block_file_size, 450 fdp->meta.encrypted_fek); 451 if (res != TEE_SUCCESS) { 452 EMSG("Failed to read and decrypt file"); 453 goto exit; 454 } 455 b->data_size = block_file_size; 456 DMSG("Successfully read and decrypt block%d from storage, size=%zd", 457 b->block_num, b->data_size); 458 exit: 459 return res; 460 } 461 462 static int flush_block_to_storage(struct tee_fs_fd *fdp, struct block *b, 463 struct tee_fs_file_meta *new_meta) 464 { 465 TEE_Result res; 466 size_t block_num = b->block_num; 467 char block_path[REE_FS_NAME_MAX]; 468 uint8_t new_version = 469 !get_backup_version_of_block(&fdp->meta, block_num); 470 471 get_block_filepath(fdp->filename, block_num, new_version, block_path); 472 473 res = encrypt_and_write_file(block_path, BLOCK_FILE, b->data, 474 b->data_size, new_meta->encrypted_fek); 475 if (res != TEE_SUCCESS) { 476 EMSG("Failed to encrypt and write block file"); 477 goto fail; 478 } 479 480 DMSG("Successfully encrypt and write block%d to storage, size=%zd", 481 b->block_num, b->data_size); 482 toggle_backup_version_of_block(new_meta, block_num); 483 484 return 0; 485 fail: 486 return -1; 487 } 488 489 static struct block *alloc_block(void) 490 { 491 struct block *c; 492 493 c = malloc(sizeof(struct block)); 494 if (!c) 495 return NULL; 496 497 c->data = malloc(BLOCK_FILE_SIZE); 498 if (!c->data) { 499 EMSG("unable to alloc memory for block data"); 500 goto exit; 501 } 502 503 c->block_num = -1; 504 c->data_size = 0; 505 506 return c; 507 508 exit: 509 free(c); 510 return NULL; 511 } 512 513 #ifdef CFG_FS_BLOCK_CACHE 514 static void free_block(struct block *b) 515 { 516 if (b) { 517 free(b->data); 518 free(b); 519 } 520 } 521 522 static inline bool is_block_data_invalid(struct block *b) 523 { 524 return (b->data_size == 0); 525 } 526 527 static void get_block_from_cache(struct block_cache *cache, 528 int block_num, struct block **out_block) 529 { 530 struct block *b, *found = NULL; 531 532 DMSG("Try to find block%d in cache", block_num); 533 TAILQ_FOREACH(b, &cache->block_lru, list) { 534 if (b->block_num == block_num) { 535 DMSG("Found in cache"); 536 found = b; 537 break; 538 } 539 } 540 541 if (found) { 542 TAILQ_REMOVE(&cache->block_lru, found, list); 543 TAILQ_INSERT_HEAD(&cache->block_lru, found, list); 544 *out_block = found; 545 return; 546 } 547 548 DMSG("Not found, reuse oldest block on LRU list"); 549 b = TAILQ_LAST(&cache->block_lru, block_head); 550 TAILQ_REMOVE(&cache->block_lru, b, list); 551 TAILQ_INSERT_HEAD(&cache->block_lru, b, list); 552 b->block_num = block_num; 553 b->data_size = 0; 554 *out_block = b; 555 } 556 557 static int init_block_cache(struct block_cache *cache) 558 { 559 struct block *b; 560 561 TAILQ_INIT(&cache->block_lru); 562 cache->cached_block_num = 0; 563 564 while (cache->cached_block_num < MAX_NUM_CACHED_BLOCKS) { 565 566 b = alloc_block(); 567 if (!b) { 568 EMSG("Failed to alloc block"); 569 goto fail; 570 } else { 571 TAILQ_INSERT_HEAD(&cache->block_lru, b, list); 572 cache->cached_block_num++; 573 } 574 } 575 return 0; 576 577 fail: 578 TAILQ_FOREACH(b, &cache->block_lru, list) 579 free_block(b); 580 return -1; 581 } 582 583 static void destroy_block_cache(struct block_cache *cache) 584 { 585 struct block *b, *next; 586 587 TAILQ_FOREACH_SAFE(b, &cache->block_lru, list, next) { 588 TAILQ_REMOVE(&cache->block_lru, b, list); 589 free_block(b); 590 } 591 } 592 #else 593 static int init_block_cache(struct block_cache *cache __unused) 594 { 595 return 0; 596 } 597 598 static void destroy_block_cache(struct block_cache *cache __unused) 599 { 600 } 601 #endif 602 603 static void write_data_to_block(struct block *b, int offset, 604 void *buf, size_t len) 605 { 606 DMSG("Write %zd bytes to block%d", len, b->block_num); 607 memcpy(b->data + offset, buf, len); 608 if (offset + len > b->data_size) { 609 b->data_size = offset + len; 610 DMSG("Extend block%d size to %zd bytes", 611 b->block_num, b->data_size); 612 } 613 } 614 615 static void read_data_from_block(struct block *b, int offset, 616 void *buf, size_t len) 617 { 618 DMSG("Read %zd bytes from block%d", len, b->block_num); 619 if (offset + len > b->data_size) 620 panic("Exceeding block size"); 621 memcpy(buf, b->data + offset, len); 622 } 623 624 #ifdef CFG_FS_BLOCK_CACHE 625 static struct block *read_block_with_cache(struct tee_fs_fd *fdp, int block_num) 626 { 627 struct block *b; 628 629 get_block_from_cache(&fdp->block_cache, block_num, &b); 630 if (is_block_data_invalid(b)) 631 if (read_block_from_storage(fdp, b)) { 632 EMSG("Unable to read block%d from storage", 633 block_num); 634 return NULL; 635 } 636 637 return b; 638 } 639 #else 640 641 static struct block *read_block_no_cache(struct tee_fs_fd *fdp, int block_num) 642 { 643 static struct block *b; 644 TEE_Result res; 645 646 if (!b) 647 b = alloc_block(); 648 b->block_num = block_num; 649 650 res = read_block_from_storage(fdp, b); 651 if (res != TEE_SUCCESS) 652 EMSG("Unable to read block%d from storage", 653 block_num); 654 655 return res != TEE_SUCCESS ? NULL : b; 656 } 657 #endif 658 659 static struct block_operations block_ops = { 660 #ifdef CFG_FS_BLOCK_CACHE 661 .read = read_block_with_cache, 662 #else 663 .read = read_block_no_cache, 664 #endif 665 .write = flush_block_to_storage, 666 }; 667 668 static int out_of_place_write(struct tee_fs_fd *fdp, const void *buf, 669 size_t len, struct tee_fs_file_meta *new_meta) 670 { 671 int start_block_num = pos_to_block_num(fdp->pos); 672 int end_block_num = pos_to_block_num(fdp->pos + len - 1); 673 size_t remain_bytes = len; 674 uint8_t *data_ptr = (uint8_t *)buf; 675 int orig_pos = fdp->pos; 676 677 while (start_block_num <= end_block_num) { 678 int offset = fdp->pos % BLOCK_FILE_SIZE; 679 struct block *b; 680 size_t size_to_write = (remain_bytes > BLOCK_FILE_SIZE) ? 681 BLOCK_FILE_SIZE : remain_bytes; 682 683 if (size_to_write + offset > BLOCK_FILE_SIZE) 684 size_to_write = BLOCK_FILE_SIZE - offset; 685 686 b = block_ops.read(fdp, start_block_num); 687 if (!b) 688 goto failed; 689 690 DMSG("Write data, offset: %d, size_to_write: %zd", 691 offset, size_to_write); 692 write_data_to_block(b, offset, data_ptr, size_to_write); 693 694 if (block_ops.write(fdp, b, new_meta)) { 695 EMSG("Unable to wrtie block%d to storage", 696 b->block_num); 697 goto failed; 698 } 699 700 data_ptr += size_to_write; 701 remain_bytes -= size_to_write; 702 start_block_num++; 703 fdp->pos += size_to_write; 704 } 705 706 if (fdp->pos > (tee_fs_off_t)new_meta->info.length) 707 new_meta->info.length = fdp->pos; 708 709 return 0; 710 failed: 711 fdp->pos = orig_pos; 712 return -1; 713 } 714 715 static inline int create_hard_link(const char *old_dir, 716 const char *new_dir, 717 const char *filename) 718 { 719 char old_path[REE_FS_NAME_MAX]; 720 char new_path[REE_FS_NAME_MAX]; 721 722 snprintf(old_path, REE_FS_NAME_MAX, "%s/%s", 723 old_dir, filename); 724 snprintf(new_path, REE_FS_NAME_MAX, "%s/%s", 725 new_dir, filename); 726 727 DMSG("%s -> %s", old_path, new_path); 728 return tee_fs_rpc_link(OPTEE_MSG_RPC_CMD_FS, old_path, new_path); 729 } 730 731 static int unlink_tee_file(const char *file) 732 { 733 int res = -1; 734 size_t len = strlen(file) + 1; 735 struct tee_fs_dirent *dirent; 736 struct tee_fs_dir *dir; 737 738 DMSG("file=%s", file); 739 740 if (len > TEE_FS_NAME_MAX) 741 goto exit; 742 743 dir = ree_fs_opendir_rpc(file); 744 if (!dir) 745 goto exit; 746 747 dirent = ree_fs_readdir_rpc(dir); 748 while (dirent) { 749 char path[REE_FS_NAME_MAX]; 750 751 snprintf(path, REE_FS_NAME_MAX, "%s/%s", 752 file, dirent->d_name); 753 754 DMSG("unlink %s", path); 755 if (tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, path) != 756 TEE_SUCCESS) { 757 ree_fs_closedir_rpc(dir); 758 res = -1; 759 goto exit; 760 } 761 dirent = ree_fs_readdir_rpc(dir); 762 } 763 764 res = ree_fs_closedir_rpc(dir); 765 if (res) 766 goto exit; 767 768 res = ree_fs_rmdir_rpc(file); 769 exit: 770 return res; 771 } 772 773 static int ree_fs_ftruncate_internal(TEE_Result *errno, struct tee_fs_fd *fdp, 774 tee_fs_off_t new_file_len); 775 776 static int ree_fs_open(TEE_Result *errno, const char *file, int flags, ...) 777 { 778 TEE_Result res; 779 int rc = -1; 780 size_t len; 781 struct tee_fs_fd *fdp = NULL; 782 783 mutex_lock(&ree_fs_mutex); 784 785 assert(errno); 786 *errno = TEE_SUCCESS; 787 788 if (!file) { 789 *errno = TEE_ERROR_BAD_PARAMETERS; 790 goto exit; 791 } 792 793 len = strlen(file) + 1; 794 if (len > TEE_FS_NAME_MAX) { 795 *errno = TEE_ERROR_BAD_PARAMETERS; 796 goto exit; 797 } 798 799 fdp = calloc(1, sizeof(struct tee_fs_fd)); 800 if (!fdp) { 801 *errno = TEE_ERROR_OUT_OF_MEMORY; 802 goto exit; 803 } 804 805 /* init internal status */ 806 fdp->flags = flags; 807 if (init_block_cache(&fdp->block_cache)) { 808 *errno = TEE_ERROR_OUT_OF_MEMORY; 809 goto exit_free_fd; 810 } 811 812 fdp->filename = malloc(len); 813 if (!fdp->filename) { 814 rc = -1; 815 *errno = TEE_ERROR_OUT_OF_MEMORY; 816 goto exit_destroy_block_cache; 817 } 818 memcpy(fdp->filename, file, len); 819 820 res = read_meta(fdp); 821 if (res == TEE_SUCCESS) { 822 if (flags & TEE_FS_O_EXCL) { 823 *errno = TEE_ERROR_ACCESS_CONFLICT; 824 goto exit_free_filename; 825 } 826 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 827 if (!(flags & TEE_FS_O_CREATE)) { 828 *errno = res; 829 goto exit_free_filename; 830 } 831 res = create_meta(fdp); 832 if (res != TEE_SUCCESS) { 833 *errno = res; 834 goto exit_free_filename; 835 } 836 } else { 837 *errno = res; 838 goto exit_free_filename; 839 } 840 841 /* return fd */ 842 rc = handle_get(&fs_handle_db, fdp); 843 if (rc < 0) 844 goto exit_free_filename; 845 fdp->fd = rc; 846 goto exit; 847 848 exit_free_filename: 849 free(fdp->filename); 850 exit_destroy_block_cache: 851 destroy_block_cache(&fdp->block_cache); 852 exit_free_fd: 853 free(fdp); 854 exit: 855 mutex_unlock(&ree_fs_mutex); 856 return rc; 857 } 858 859 static int ree_fs_close(int fd) 860 { 861 int res = -1; 862 struct tee_fs_fd *fdp; 863 864 mutex_lock(&ree_fs_mutex); 865 866 fdp = handle_lookup(&fs_handle_db, fd); 867 if (!fdp) 868 goto exit; 869 870 handle_put(&fs_handle_db, fdp->fd); 871 872 destroy_block_cache(&fdp->block_cache); 873 free(fdp->filename); 874 free(fdp); 875 876 exit: 877 mutex_unlock(&ree_fs_mutex); 878 return res; 879 } 880 881 static tee_fs_off_t ree_fs_lseek(TEE_Result *errno, int fd, 882 tee_fs_off_t offset, int whence) 883 { 884 tee_fs_off_t res = -1; 885 tee_fs_off_t new_pos; 886 size_t filelen; 887 struct tee_fs_fd *fdp; 888 889 mutex_lock(&ree_fs_mutex); 890 891 assert(errno); 892 *errno = TEE_SUCCESS; 893 894 fdp = handle_lookup(&fs_handle_db, fd); 895 if (!fdp) { 896 *errno = TEE_ERROR_BAD_PARAMETERS; 897 goto exit; 898 } 899 900 DMSG("offset=%d, whence=%d", (int)offset, whence); 901 902 filelen = fdp->meta.info.length; 903 904 switch (whence) { 905 case TEE_FS_SEEK_SET: 906 new_pos = offset; 907 break; 908 909 case TEE_FS_SEEK_CUR: 910 new_pos = fdp->pos + offset; 911 break; 912 913 case TEE_FS_SEEK_END: 914 new_pos = filelen + offset; 915 break; 916 917 default: 918 *errno = TEE_ERROR_BAD_PARAMETERS; 919 goto exit; 920 } 921 922 if (new_pos < 0) 923 new_pos = 0; 924 925 if (new_pos > TEE_DATA_MAX_POSITION) { 926 EMSG("Position is beyond TEE_DATA_MAX_POSITION"); 927 *errno = TEE_ERROR_BAD_PARAMETERS; 928 goto exit; 929 } 930 931 res = fdp->pos = new_pos; 932 exit: 933 mutex_unlock(&ree_fs_mutex); 934 return res; 935 } 936 937 /* 938 * To ensure atomic truncate operation, we can: 939 * 940 * - update file length to new length 941 * - commit new meta 942 * - free unused blocks 943 * 944 * To ensure atomic extend operation, we can: 945 * 946 * - update file length to new length 947 * - allocate and fill zero data to new blocks 948 * - commit new meta 949 * 950 * Any failure before committing new meta is considered as 951 * update failed, and the file content will not be updated 952 */ 953 static int ree_fs_ftruncate_internal(TEE_Result *errno, struct tee_fs_fd *fdp, 954 tee_fs_off_t new_file_len) 955 { 956 int res = -1; 957 size_t old_file_len = fdp->meta.info.length; 958 struct tee_fs_file_meta new_meta; 959 uint8_t *buf = NULL; 960 961 assert(errno); 962 *errno = TEE_SUCCESS; 963 964 if (!fdp) { 965 *errno = TEE_ERROR_BAD_PARAMETERS; 966 res = -1; 967 goto exit; 968 } 969 970 if (fdp->flags & TEE_FS_O_RDONLY) { 971 *errno = TEE_ERROR_BAD_PARAMETERS; 972 EMSG("Read only"); 973 res = -1; 974 goto exit; 975 } 976 977 if ((size_t)new_file_len == old_file_len) { 978 DMSG("Ignore due to file length does not changed"); 979 res = 0; 980 goto exit; 981 } 982 983 if (new_file_len > MAX_FILE_SIZE) { 984 *errno = TEE_ERROR_BAD_PARAMETERS; 985 EMSG("Over maximum file size(%d)", MAX_FILE_SIZE); 986 res = -1; 987 goto exit; 988 } 989 990 new_meta = fdp->meta; 991 new_meta.info.length = new_file_len; 992 993 if ((size_t)new_file_len < old_file_len) { 994 int old_block_num = get_last_block_num(old_file_len); 995 int new_block_num = get_last_block_num(new_file_len); 996 997 DMSG("Truncate file length to %zu", (size_t)new_file_len); 998 999 res = commit_meta_file(fdp, &new_meta); 1000 if (res < 0) { 1001 *errno = TEE_ERROR_CORRUPT_OBJECT; 1002 EMSG("Failed to commit meta file"); 1003 goto free; 1004 } 1005 1006 /* now we are safe to free unused blocks */ 1007 while (old_block_num > new_block_num) { 1008 if (remove_block_file(fdp, old_block_num)) { 1009 IMSG("Warning: Failed to free block: %d", 1010 old_block_num); 1011 } 1012 1013 old_block_num--; 1014 } 1015 1016 } else { 1017 size_t ext_len = new_file_len - old_file_len; 1018 int orig_pos = fdp->pos; 1019 1020 buf = malloc(BLOCK_FILE_SIZE); 1021 if (!buf) { 1022 *errno = TEE_ERROR_OUT_OF_MEMORY; 1023 EMSG("Failed to allocate buffer, size=%d", 1024 BLOCK_FILE_SIZE); 1025 res = -1; 1026 goto free; 1027 } 1028 1029 memset(buf, 0x0, BLOCK_FILE_SIZE); 1030 1031 DMSG("Extend file length to %zu", (size_t)new_file_len); 1032 1033 fdp->pos = old_file_len; 1034 1035 res = 0; 1036 while (ext_len > 0) { 1037 size_t data_len = (ext_len > BLOCK_FILE_SIZE) ? 1038 BLOCK_FILE_SIZE : ext_len; 1039 1040 DMSG("fill len=%zu", data_len); 1041 res = out_of_place_write(fdp, (void *)buf, 1042 data_len, &new_meta); 1043 if (res < 0) { 1044 *errno = TEE_ERROR_CORRUPT_OBJECT; 1045 EMSG("Failed to fill data"); 1046 break; 1047 } 1048 1049 ext_len -= data_len; 1050 } 1051 1052 fdp->pos = orig_pos; 1053 1054 if (res == 0) { 1055 res = commit_meta_file(fdp, &new_meta); 1056 if (res < 0) { 1057 *errno = TEE_ERROR_CORRUPT_OBJECT; 1058 EMSG("Failed to commit meta file"); 1059 } 1060 } 1061 } 1062 1063 free: 1064 free(buf); 1065 1066 exit: 1067 return res; 1068 } 1069 1070 static int ree_fs_read(TEE_Result *errno, int fd, void *buf, size_t len) 1071 { 1072 int res = -1; 1073 int start_block_num; 1074 int end_block_num; 1075 size_t remain_bytes = len; 1076 uint8_t *data_ptr = buf; 1077 struct tee_fs_fd *fdp; 1078 1079 mutex_lock(&ree_fs_mutex); 1080 1081 assert(errno); 1082 *errno = TEE_SUCCESS; 1083 1084 fdp = handle_lookup(&fs_handle_db, fd); 1085 if (!fdp) { 1086 *errno = TEE_ERROR_BAD_PARAMETERS; 1087 goto exit; 1088 } 1089 1090 if ((fdp->pos + len) < len || 1091 fdp->pos > (tee_fs_off_t)fdp->meta.info.length) 1092 len = 0; 1093 else if (fdp->pos + len > fdp->meta.info.length) 1094 len = fdp->meta.info.length - fdp->pos; 1095 1096 if (!len) { 1097 res = 0; 1098 goto exit; 1099 } 1100 1101 if (!buf) { 1102 *errno = TEE_ERROR_BAD_PARAMETERS; 1103 goto exit; 1104 } 1105 1106 if (fdp->flags & TEE_FS_O_WRONLY) { 1107 *errno = TEE_ERROR_ACCESS_CONFLICT; 1108 goto exit; 1109 } 1110 1111 DMSG("%s, data len=%zu", fdp->filename, len); 1112 1113 start_block_num = pos_to_block_num(fdp->pos); 1114 end_block_num = pos_to_block_num(fdp->pos + len - 1); 1115 DMSG("start_block_num:%d, end_block_num:%d", 1116 start_block_num, end_block_num); 1117 1118 while (start_block_num <= end_block_num) { 1119 struct block *b; 1120 int offset = fdp->pos % BLOCK_FILE_SIZE; 1121 size_t size_to_read = remain_bytes > BLOCK_FILE_SIZE ? 1122 BLOCK_FILE_SIZE : remain_bytes; 1123 1124 if (size_to_read + offset > BLOCK_FILE_SIZE) 1125 size_to_read = BLOCK_FILE_SIZE - offset; 1126 1127 DMSG("block_num:%d, offset:%d, size_to_read: %zd", 1128 start_block_num, offset, size_to_read); 1129 1130 b = block_ops.read(fdp, start_block_num); 1131 if (!b) { 1132 *errno = TEE_ERROR_CORRUPT_OBJECT; 1133 goto exit; 1134 } 1135 1136 read_data_from_block(b, offset, data_ptr, size_to_read); 1137 data_ptr += size_to_read; 1138 remain_bytes -= size_to_read; 1139 fdp->pos += size_to_read; 1140 1141 start_block_num++; 1142 } 1143 res = 0; 1144 exit: 1145 mutex_unlock(&ree_fs_mutex); 1146 return (res < 0) ? res : (int)len; 1147 } 1148 1149 /* 1150 * To ensure atomicity of write operation, we need to 1151 * do the following steps: 1152 * (The sequence of operations is very important) 1153 * 1154 * - Create a new backup version of meta file as a copy 1155 * of current meta file. 1156 * - For each blocks to write: 1157 * - Create new backup version for current block. 1158 * - Write data to new backup version. 1159 * - Update the new meta file accordingly. 1160 * - Write the new meta file. 1161 * 1162 * (Any failure in above steps is considered as update failed, 1163 * and the file content will not be updated) 1164 * 1165 * After previous step the update is considered complete, but 1166 * we should do the following clean-up step(s): 1167 * 1168 * - Delete old meta file. 1169 * - Remove old block files. 1170 * 1171 * (Any failure in above steps is considered as a successfully 1172 * update) 1173 */ 1174 static int ree_fs_write(TEE_Result *errno, int fd, const void *buf, size_t len) 1175 { 1176 int res = -1; 1177 struct tee_fs_file_meta new_meta; 1178 struct tee_fs_fd *fdp; 1179 size_t file_size; 1180 int orig_pos; 1181 1182 mutex_lock(&ree_fs_mutex); 1183 1184 assert(errno); 1185 *errno = TEE_SUCCESS; 1186 1187 fdp = handle_lookup(&fs_handle_db, fd); 1188 if (!fdp) { 1189 *errno = TEE_ERROR_BAD_PARAMETERS; 1190 goto exit; 1191 } 1192 if (!len) { 1193 res = 0; 1194 goto exit; 1195 } 1196 if (!buf) { 1197 *errno = TEE_ERROR_BAD_PARAMETERS; 1198 goto exit; 1199 } 1200 1201 file_size = fdp->meta.info.length; 1202 orig_pos = fdp->pos; 1203 1204 if (fdp->flags & TEE_FS_O_RDONLY) { 1205 EMSG("Write to a read-only file, denied"); 1206 *errno = TEE_ERROR_ACCESS_CONFLICT; 1207 goto exit; 1208 } 1209 1210 if ((fdp->pos + len) > MAX_FILE_SIZE) { 1211 EMSG("Over maximum file size(%d)", MAX_FILE_SIZE); 1212 *errno = TEE_ERROR_BAD_PARAMETERS; 1213 goto exit; 1214 } 1215 1216 DMSG("%s, data len=%zu", fdp->filename, len); 1217 if (file_size < (size_t)fdp->pos) { 1218 DMSG("File hole detected, try to extend file size"); 1219 res = ree_fs_ftruncate_internal(errno, fdp, fdp->pos); 1220 if (res < 0) 1221 goto exit; 1222 } 1223 1224 new_meta = fdp->meta; 1225 res = out_of_place_write(fdp, buf, len, &new_meta); 1226 if (res < 0) { 1227 *errno = TEE_ERROR_CORRUPT_OBJECT; 1228 } else { 1229 int r; 1230 int start_block_num; 1231 int end_block_num; 1232 1233 r = commit_meta_file(fdp, &new_meta); 1234 if (r < 0) { 1235 *errno = TEE_ERROR_CORRUPT_OBJECT; 1236 res = -1; 1237 } 1238 1239 /* we are safe to free old blocks */ 1240 start_block_num = pos_to_block_num(orig_pos); 1241 end_block_num = pos_to_block_num(fdp->pos - 1); 1242 while (start_block_num <= end_block_num) { 1243 if (remove_outdated_block(fdp, start_block_num)) 1244 IMSG("Warning: Failed to free old block: %d", 1245 start_block_num); 1246 1247 start_block_num++; 1248 } 1249 } 1250 exit: 1251 mutex_unlock(&ree_fs_mutex); 1252 return (res < 0) ? res : (int)len; 1253 } 1254 1255 /* 1256 * To ensure atomicity of rename operation, we need to 1257 * do the following steps: 1258 * 1259 * - Create a new folder that represents the renamed TEE file 1260 * - For each REE block files, create a hard link under the just 1261 * created folder (new TEE file) 1262 * - Now we are ready to commit meta, create hard link for the 1263 * meta file 1264 * 1265 * (Any failure in above steps is considered as update failed, 1266 * and the file content will not be updated) 1267 * 1268 * After previous step the update is considered complete, but 1269 * we should do the following clean-up step(s): 1270 * 1271 * - Unlink all REE files represents the old TEE file (including 1272 * meta and block files) 1273 * 1274 * (Any failure in above steps is considered as a successfully 1275 * update) 1276 */ 1277 static int ree_fs_rename_internal(const char *old, const char *new) 1278 { 1279 int res = -1; 1280 size_t old_len; 1281 size_t new_len; 1282 size_t meta_count = 0; 1283 struct tee_fs_dir *old_dir; 1284 struct tee_fs_dirent *dirent; 1285 char *meta_filename = NULL; 1286 1287 if (!old || !new) 1288 return -1; 1289 1290 DMSG("old=%s, new=%s", old, new); 1291 1292 old_len = strlen(old) + 1; 1293 new_len = strlen(new) + 1; 1294 1295 if (old_len > TEE_FS_NAME_MAX || new_len > TEE_FS_NAME_MAX) 1296 goto exit; 1297 1298 res = ree_fs_mkdir_rpc(new, 1299 TEE_FS_S_IRUSR | TEE_FS_S_IWUSR); 1300 if (res) 1301 goto exit; 1302 1303 old_dir = ree_fs_opendir_rpc(old); 1304 if (!old_dir) 1305 goto exit; 1306 1307 dirent = ree_fs_readdir_rpc(old_dir); 1308 while (dirent) { 1309 if (!strncmp(dirent->d_name, "meta.", 5)) { 1310 meta_filename = strdup(dirent->d_name); 1311 meta_count++; 1312 } else { 1313 res = create_hard_link(old, new, dirent->d_name); 1314 if (res) 1315 goto exit_close_old_dir; 1316 } 1317 1318 dirent = ree_fs_readdir_rpc(old_dir); 1319 } 1320 1321 /* finally, link the meta file, rename operation completed */ 1322 if (!meta_filename) 1323 panic("no meta file"); 1324 1325 /* 1326 * TODO: This will cause memory leakage at previous strdup() 1327 * if we accidently have two meta files in a TEE file. 1328 * 1329 * It's not easy to handle the case above (e.g. Which meta file 1330 * should be linked first? What to do if a power cut happened 1331 * during creating links for the two meta files?) 1332 * 1333 * We will solve this issue using another approach: merging 1334 * both meta and block files into a single REE file. This approach 1335 * can completely remove ree_fs_rename(). We can simply 1336 * rename TEE file using REE rename() system call, which is also 1337 * atomic. 1338 */ 1339 if (meta_count > 1) 1340 EMSG("Warning: more than one meta file in your TEE file\n" 1341 "This will cause memory leakage."); 1342 1343 res = create_hard_link(old, new, meta_filename); 1344 if (res) 1345 goto exit_close_old_dir; 1346 1347 /* we are safe now, remove old TEE file */ 1348 unlink_tee_file(old); 1349 1350 exit_close_old_dir: 1351 ree_fs_closedir_rpc(old_dir); 1352 exit: 1353 free(meta_filename); 1354 return res; 1355 } 1356 1357 static int ree_fs_rename(const char *old, const char *new) 1358 { 1359 int res; 1360 1361 mutex_lock(&ree_fs_mutex); 1362 res = ree_fs_rename_internal(old, new); 1363 mutex_unlock(&ree_fs_mutex); 1364 1365 return res; 1366 } 1367 1368 /* 1369 * To ensure atomic unlink operation, we can simply 1370 * split the unlink operation into: 1371 * 1372 * - rename("file", "file.trash"); 1373 * 1374 * (Any failure in above steps is considered as update failed, 1375 * and the file content will not be updated) 1376 * 1377 * After previous step the update is considered complete, but 1378 * we should do the following clean-up step(s): 1379 * 1380 * - unlink("file.trash"); 1381 * 1382 * (Any failure in above steps is considered as a successfully 1383 * update) 1384 */ 1385 static int ree_fs_unlink(const char *file) 1386 { 1387 int res = -1; 1388 char trash_file[TEE_FS_NAME_MAX + 6]; 1389 1390 if (!file) 1391 return -1; 1392 1393 snprintf(trash_file, TEE_FS_NAME_MAX + 6, "%s.trash", 1394 file); 1395 1396 mutex_lock(&ree_fs_mutex); 1397 1398 res = ree_fs_rename_internal(file, trash_file); 1399 if (res < 0) 1400 goto exit; 1401 1402 unlink_tee_file(trash_file); 1403 1404 exit: 1405 mutex_unlock(&ree_fs_mutex); 1406 return res; 1407 } 1408 1409 static int ree_fs_ftruncate(TEE_Result *errno, int fd, tee_fs_off_t length) 1410 { 1411 struct tee_fs_fd *fdp; 1412 int res; 1413 1414 mutex_lock(&ree_fs_mutex); 1415 fdp = handle_lookup(&fs_handle_db, fd); 1416 res = ree_fs_ftruncate_internal(errno, fdp, length); 1417 mutex_unlock(&ree_fs_mutex); 1418 1419 return res; 1420 } 1421 1422 const struct tee_file_operations ree_fs_ops = { 1423 .open = ree_fs_open, 1424 .close = ree_fs_close, 1425 .read = ree_fs_read, 1426 .write = ree_fs_write, 1427 .lseek = ree_fs_lseek, 1428 .ftruncate = ree_fs_ftruncate, 1429 .rename = ree_fs_rename, 1430 .unlink = ree_fs_unlink, 1431 .mkdir = ree_fs_mkdir_rpc, 1432 .opendir = ree_fs_opendir_rpc, 1433 .closedir = ree_fs_closedir_rpc, 1434 .readdir = ree_fs_readdir_rpc, 1435 .rmdir = ree_fs_rmdir_rpc, 1436 .access = ree_fs_access_rpc 1437 }; 1438