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