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