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 /* 49 * This file implements the tee_file_operations structure for a secure 50 * filesystem based on single file in normal world. 51 * 52 * All fields in the REE file are duplicated with two versions 0 and 1. The 53 * active meta-data block is selected by the lowest bit in the 54 * meta-counter. The active file block is selected by corresponding bit 55 * number in struct tee_fs_file_info.backup_version_table. 56 * 57 * The atomicity of each operation is ensured by updating meta-counter when 58 * everything in the secondary blocks (both meta-data and file-data blocks) 59 * are successfully written. The main purpose of the code below is to 60 * perform block encryption and authentication of the file data, and 61 * properly handle seeking through the file. One file (in the sense of 62 * struct tee_file_operations) maps to one file in the REE filesystem, and 63 * has the following structure: 64 * 65 * [ 4 bytes meta-counter] 66 * [ meta-data version 0][ meta-data version 1 ] 67 * [ Block 0 version 0 ][ Block 0 version 1 ] 68 * [ Block 1 version 0 ][ Block 1 version 1 ] 69 * ... 70 * [ Block n version 0 ][ Block n version 1 ] 71 * 72 * One meta-data block is built up as: 73 * [ struct meta_header | struct tee_fs_get_header_size ] 74 * 75 * One data block is built up as: 76 * [ struct block_header | BLOCK_FILE_SIZE bytes ] 77 * 78 * struct meta_header and struct block_header are defined in 79 * tee_fs_key_manager.h. 80 * 81 */ 82 83 #define MAX_NUM_CACHED_BLOCKS 1 84 85 86 #define MAX_FILE_SIZE (BLOCK_FILE_SIZE * NUM_BLOCKS_PER_FILE) 87 88 TAILQ_HEAD(block_head, block); 89 90 struct block { 91 TAILQ_ENTRY(block) list; 92 int block_num; 93 uint8_t *data; 94 }; 95 96 struct block_cache { 97 struct block_head block_lru; 98 uint8_t cached_block_num; 99 }; 100 101 struct tee_fs_fd { 102 uint32_t meta_counter; 103 struct tee_fs_file_meta meta; 104 tee_fs_off_t pos; 105 uint32_t flags; 106 bool is_new_file; 107 int fd; 108 struct block_cache block_cache; 109 }; 110 111 static inline int pos_to_block_num(int position) 112 { 113 return position >> BLOCK_FILE_SHIFT; 114 } 115 116 static inline int get_last_block_num(size_t size) 117 { 118 return pos_to_block_num(size - 1); 119 } 120 121 static bool get_backup_version_of_block(struct tee_fs_file_meta *meta, 122 size_t block_num) 123 { 124 uint32_t index = (block_num / 32); 125 uint32_t block_mask = 1 << (block_num % 32); 126 127 return !!(meta->info.backup_version_table[index] & block_mask); 128 } 129 130 static inline void toggle_backup_version_of_block( 131 struct tee_fs_file_meta *meta, 132 size_t block_num) 133 { 134 uint32_t index = (block_num / 32); 135 uint32_t block_mask = 1 << (block_num % 32); 136 137 meta->info.backup_version_table[index] ^= block_mask; 138 } 139 140 struct block_operations { 141 142 /* 143 * Read a block from REE File System which is corresponding 144 * to the given block_num. 145 */ 146 struct block *(*read)(struct tee_fs_fd *fdp, int block_num); 147 148 /* 149 * Write the given block to REE File System 150 */ 151 int (*write)(struct tee_fs_fd *fdp, struct block *b, 152 struct tee_fs_file_meta *new_meta); 153 }; 154 155 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; 156 157 static TEE_Result ree_fs_opendir_rpc(const char *name, struct tee_fs_dir **d) 158 159 { 160 return tee_fs_rpc_new_opendir(OPTEE_MSG_RPC_CMD_FS, name, d); 161 } 162 163 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 164 { 165 if (d) 166 tee_fs_rpc_new_closedir(OPTEE_MSG_RPC_CMD_FS, d); 167 } 168 169 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 170 struct tee_fs_dirent **ent) 171 { 172 return tee_fs_rpc_new_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent); 173 } 174 175 static size_t meta_size(void) 176 { 177 return tee_fs_get_header_size(META_FILE) + 178 sizeof(struct tee_fs_file_meta); 179 } 180 181 static size_t meta_pos_raw(struct tee_fs_fd *fdp, bool active) 182 { 183 size_t offs = sizeof(uint32_t); 184 185 if ((fdp->meta_counter & 1) == active) 186 offs += meta_size(); 187 return offs; 188 } 189 190 static size_t block_size_raw(void) 191 { 192 return tee_fs_get_header_size(BLOCK_FILE) + BLOCK_FILE_SIZE; 193 } 194 195 static size_t block_pos_raw(struct tee_fs_file_meta *meta, size_t block_num, 196 bool active) 197 { 198 size_t n = block_num * 2; 199 200 if (active == get_backup_version_of_block(meta, block_num)) 201 n++; 202 203 return sizeof(uint32_t) + meta_size() * 2 + n * block_size_raw(); 204 } 205 206 /* 207 * encrypted_fek: as input for META_FILE and BLOCK_FILE 208 */ 209 static TEE_Result encrypt_and_write_file(struct tee_fs_fd *fdp, 210 enum tee_fs_file_type file_type, size_t offs, 211 void *data_in, size_t data_in_size, 212 uint8_t *encrypted_fek) 213 { 214 TEE_Result res; 215 struct tee_fs_rpc_operation op; 216 void *ciphertext; 217 size_t header_size = tee_fs_get_header_size(file_type); 218 size_t ciphertext_size = header_size + data_in_size; 219 220 221 res = tee_fs_rpc_new_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 222 offs, ciphertext_size, &ciphertext); 223 if (res != TEE_SUCCESS) 224 return res; 225 226 res = tee_fs_encrypt_file(file_type, data_in, data_in_size, 227 ciphertext, &ciphertext_size, encrypted_fek); 228 if (res != TEE_SUCCESS) 229 return res; 230 231 return tee_fs_rpc_new_write_final(&op); 232 } 233 234 /* 235 * encrypted_fek: as output for META_FILE 236 * as input for BLOCK_FILE 237 */ 238 static TEE_Result read_and_decrypt_file(struct tee_fs_fd *fdp, 239 enum tee_fs_file_type file_type, size_t offs, 240 void *data_out, size_t *data_out_size, 241 uint8_t *encrypted_fek) 242 { 243 TEE_Result res; 244 struct tee_fs_rpc_operation op; 245 size_t bytes; 246 void *ciphertext; 247 248 bytes = *data_out_size + tee_fs_get_header_size(file_type); 249 res = tee_fs_rpc_new_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, offs, 250 bytes, &ciphertext); 251 if (res != TEE_SUCCESS) 252 return res; 253 254 res = tee_fs_rpc_new_read_final(&op, &bytes); 255 if (res != TEE_SUCCESS) 256 return res; 257 258 if (!bytes) { 259 *data_out_size = 0; 260 return TEE_SUCCESS; 261 } 262 263 res = tee_fs_decrypt_file(file_type, ciphertext, bytes, data_out, 264 data_out_size, encrypted_fek); 265 if (res != TEE_SUCCESS) 266 return TEE_ERROR_CORRUPT_OBJECT; 267 return TEE_SUCCESS; 268 } 269 270 static TEE_Result write_meta_file(struct tee_fs_fd *fdp, 271 struct tee_fs_file_meta *meta) 272 { 273 size_t offs = meta_pos_raw(fdp, false); 274 275 return encrypt_and_write_file(fdp, META_FILE, offs, 276 (void *)&meta->info, sizeof(meta->info), 277 meta->encrypted_fek); 278 } 279 280 static TEE_Result write_meta_counter(struct tee_fs_fd *fdp) 281 { 282 TEE_Result res; 283 struct tee_fs_rpc_operation op; 284 size_t bytes = sizeof(uint32_t); 285 void *data; 286 287 res = tee_fs_rpc_new_write_init(&op, OPTEE_MSG_RPC_CMD_FS, 288 fdp->fd, 0, bytes, &data); 289 if (res != TEE_SUCCESS) 290 return res; 291 292 memcpy(data, &fdp->meta_counter, bytes); 293 294 return tee_fs_rpc_new_write_final(&op); 295 } 296 297 static TEE_Result create_meta(struct tee_fs_fd *fdp, const char *fname) 298 { 299 TEE_Result res; 300 301 memset(fdp->meta.info.backup_version_table, 0xff, 302 sizeof(fdp->meta.info.backup_version_table)); 303 fdp->meta.info.length = 0; 304 305 res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE); 306 if (res != TEE_SUCCESS) 307 return res; 308 309 res = tee_fs_rpc_new_create(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd); 310 if (res != TEE_SUCCESS) 311 return res; 312 313 fdp->meta.counter = fdp->meta_counter; 314 315 res = write_meta_file(fdp, &fdp->meta); 316 if (res != TEE_SUCCESS) 317 return res; 318 return write_meta_counter(fdp); 319 } 320 321 static TEE_Result commit_meta_file(struct tee_fs_fd *fdp, 322 struct tee_fs_file_meta *new_meta) 323 { 324 TEE_Result res; 325 326 new_meta->counter = fdp->meta_counter + 1; 327 328 res = write_meta_file(fdp, new_meta); 329 if (res != TEE_SUCCESS) 330 return res; 331 332 /* 333 * From now on the new meta is successfully committed, 334 * change tee_fs_fd accordingly 335 */ 336 fdp->meta = *new_meta; 337 fdp->meta_counter = fdp->meta.counter; 338 339 return write_meta_counter(fdp); 340 } 341 342 static TEE_Result read_meta_file(struct tee_fs_fd *fdp, 343 struct tee_fs_file_meta *meta) 344 { 345 size_t meta_info_size = sizeof(struct tee_fs_file_info); 346 size_t offs = meta_pos_raw(fdp, true); 347 348 return read_and_decrypt_file(fdp, META_FILE, offs, 349 &meta->info, &meta_info_size, 350 meta->encrypted_fek); 351 } 352 353 static TEE_Result read_meta_counter(struct tee_fs_fd *fdp) 354 { 355 TEE_Result res; 356 struct tee_fs_rpc_operation op; 357 void *data; 358 size_t bytes = sizeof(uint32_t); 359 360 res = tee_fs_rpc_new_read_init(&op, OPTEE_MSG_RPC_CMD_FS, 361 fdp->fd, 0, bytes, &data); 362 if (res != TEE_SUCCESS) 363 return res; 364 365 res = tee_fs_rpc_new_read_final(&op, &bytes); 366 if (res != TEE_SUCCESS) 367 return res; 368 369 if (bytes != sizeof(uint32_t)) 370 return TEE_ERROR_CORRUPT_OBJECT; 371 372 memcpy(&fdp->meta_counter, data, bytes); 373 374 return TEE_SUCCESS; 375 } 376 377 static TEE_Result read_meta(struct tee_fs_fd *fdp, const char *fname) 378 { 379 TEE_Result res; 380 381 res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd); 382 if (res != TEE_SUCCESS) 383 return res; 384 385 res = read_meta_counter(fdp); 386 if (res != TEE_SUCCESS) 387 return res; 388 389 return read_meta_file(fdp, &fdp->meta); 390 } 391 392 static bool is_block_file_exist(struct tee_fs_file_meta *meta, 393 size_t block_num) 394 { 395 size_t file_size = meta->info.length; 396 397 if (file_size == 0) 398 return false; 399 400 return (block_num <= (size_t)get_last_block_num(file_size)); 401 } 402 403 static TEE_Result read_block_from_storage(struct tee_fs_fd *fdp, 404 struct block *b) 405 { 406 TEE_Result res = TEE_SUCCESS; 407 uint8_t *plaintext = b->data; 408 size_t block_file_size = BLOCK_FILE_SIZE; 409 size_t offs = block_pos_raw(&fdp->meta, b->block_num, true); 410 411 if (!is_block_file_exist(&fdp->meta, b->block_num)) 412 goto exit; 413 414 res = read_and_decrypt_file(fdp, BLOCK_FILE, offs, plaintext, 415 &block_file_size, fdp->meta.encrypted_fek); 416 if (res != TEE_SUCCESS) { 417 EMSG("Failed to read and decrypt file"); 418 goto exit; 419 } 420 if (block_file_size != BLOCK_FILE_SIZE) 421 return TEE_ERROR_GENERIC; 422 DMSG("Successfully read and decrypt block%d from storage", 423 b->block_num); 424 exit: 425 return res; 426 } 427 428 static int flush_block_to_storage(struct tee_fs_fd *fdp, struct block *b, 429 struct tee_fs_file_meta *new_meta) 430 { 431 TEE_Result res; 432 size_t block_num = b->block_num; 433 size_t offs = block_pos_raw(&fdp->meta, b->block_num, false); 434 435 res = encrypt_and_write_file(fdp, BLOCK_FILE, offs, b->data, 436 BLOCK_FILE_SIZE, new_meta->encrypted_fek); 437 if (res != TEE_SUCCESS) { 438 EMSG("Failed to encrypt and write block file"); 439 goto fail; 440 } 441 442 DMSG("Successfully encrypt and write block%d to storage", 443 b->block_num); 444 toggle_backup_version_of_block(new_meta, block_num); 445 446 return 0; 447 fail: 448 return -1; 449 } 450 451 static struct block *alloc_block(void) 452 { 453 struct block *c; 454 455 c = malloc(sizeof(struct block)); 456 if (!c) 457 return NULL; 458 459 c->data = malloc(BLOCK_FILE_SIZE); 460 if (!c->data) { 461 EMSG("unable to alloc memory for block data"); 462 goto exit; 463 } 464 465 c->block_num = -1; 466 467 return c; 468 469 exit: 470 free(c); 471 return NULL; 472 } 473 474 #ifdef CFG_FS_BLOCK_CACHE 475 static void free_block(struct block *b) 476 { 477 if (b) { 478 free(b->data); 479 free(b); 480 } 481 } 482 483 static inline bool is_block_data_invalid(struct block *b) 484 { 485 return (b->data_size == 0); 486 } 487 488 static void get_block_from_cache(struct block_cache *cache, 489 int block_num, struct block **out_block) 490 { 491 struct block *b, *found = NULL; 492 493 DMSG("Try to find block%d in cache", block_num); 494 TAILQ_FOREACH(b, &cache->block_lru, list) { 495 if (b->block_num == block_num) { 496 DMSG("Found in cache"); 497 found = b; 498 break; 499 } 500 } 501 502 if (found) { 503 TAILQ_REMOVE(&cache->block_lru, found, list); 504 TAILQ_INSERT_HEAD(&cache->block_lru, found, list); 505 *out_block = found; 506 return; 507 } 508 509 DMSG("Not found, reuse oldest block on LRU list"); 510 b = TAILQ_LAST(&cache->block_lru, block_head); 511 TAILQ_REMOVE(&cache->block_lru, b, list); 512 TAILQ_INSERT_HEAD(&cache->block_lru, b, list); 513 b->block_num = block_num; 514 b->data_size = 0; 515 *out_block = b; 516 } 517 518 static int init_block_cache(struct block_cache *cache) 519 { 520 struct block *b; 521 522 TAILQ_INIT(&cache->block_lru); 523 cache->cached_block_num = 0; 524 525 while (cache->cached_block_num < MAX_NUM_CACHED_BLOCKS) { 526 527 b = alloc_block(); 528 if (!b) { 529 EMSG("Failed to alloc block"); 530 goto fail; 531 } else { 532 TAILQ_INSERT_HEAD(&cache->block_lru, b, list); 533 cache->cached_block_num++; 534 } 535 } 536 return 0; 537 538 fail: 539 TAILQ_FOREACH(b, &cache->block_lru, list) 540 free_block(b); 541 return -1; 542 } 543 544 static void destroy_block_cache(struct block_cache *cache) 545 { 546 struct block *b, *next; 547 548 TAILQ_FOREACH_SAFE(b, &cache->block_lru, list, next) { 549 TAILQ_REMOVE(&cache->block_lru, b, list); 550 free_block(b); 551 } 552 } 553 #else 554 static int init_block_cache(struct block_cache *cache __unused) 555 { 556 return 0; 557 } 558 559 static void destroy_block_cache(struct block_cache *cache __unused) 560 { 561 } 562 #endif 563 564 static void write_data_to_block(struct block *b, int offset, 565 void *buf, size_t len) 566 { 567 DMSG("Write %zd bytes to block%d", len, b->block_num); 568 memcpy(b->data + offset, buf, len); 569 } 570 571 static void read_data_from_block(struct block *b, int offset, 572 void *buf, size_t len) 573 { 574 DMSG("Read %zd bytes from block%d", len, b->block_num); 575 memcpy(buf, b->data + offset, len); 576 } 577 578 #ifdef CFG_FS_BLOCK_CACHE 579 static struct block *read_block_with_cache(struct tee_fs_fd *fdp, int block_num) 580 { 581 struct block *b; 582 583 get_block_from_cache(&fdp->block_cache, block_num, &b); 584 if (is_block_data_invalid(b)) 585 if (read_block_from_storage(fdp, b)) { 586 EMSG("Unable to read block%d from storage", 587 block_num); 588 return NULL; 589 } 590 591 return b; 592 } 593 #else 594 595 static struct block *read_block_no_cache(struct tee_fs_fd *fdp, int block_num) 596 { 597 static struct block *b; 598 TEE_Result res; 599 600 if (!b) 601 b = alloc_block(); 602 b->block_num = block_num; 603 604 res = read_block_from_storage(fdp, b); 605 if (res != TEE_SUCCESS) 606 EMSG("Unable to read block%d from storage", 607 block_num); 608 609 return res != TEE_SUCCESS ? NULL : b; 610 } 611 #endif 612 613 static struct block_operations block_ops = { 614 #ifdef CFG_FS_BLOCK_CACHE 615 .read = read_block_with_cache, 616 #else 617 .read = read_block_no_cache, 618 #endif 619 .write = flush_block_to_storage, 620 }; 621 622 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, const void *buf, 623 size_t len, struct tee_fs_file_meta *new_meta) 624 { 625 int start_block_num = pos_to_block_num(fdp->pos); 626 int end_block_num = pos_to_block_num(fdp->pos + len - 1); 627 size_t remain_bytes = len; 628 uint8_t *data_ptr = (uint8_t *)buf; 629 int orig_pos = fdp->pos; 630 631 while (start_block_num <= end_block_num) { 632 int offset = fdp->pos % BLOCK_FILE_SIZE; 633 struct block *b; 634 size_t size_to_write = (remain_bytes > BLOCK_FILE_SIZE) ? 635 BLOCK_FILE_SIZE : remain_bytes; 636 637 if (size_to_write + offset > BLOCK_FILE_SIZE) 638 size_to_write = BLOCK_FILE_SIZE - offset; 639 640 b = block_ops.read(fdp, start_block_num); 641 if (!b) 642 goto failed; 643 644 DMSG("Write data, offset: %d, size_to_write: %zd", 645 offset, size_to_write); 646 write_data_to_block(b, offset, data_ptr, size_to_write); 647 648 if (block_ops.write(fdp, b, new_meta)) { 649 EMSG("Unable to wrtie block%d to storage", 650 b->block_num); 651 goto failed; 652 } 653 654 data_ptr += size_to_write; 655 remain_bytes -= size_to_write; 656 start_block_num++; 657 fdp->pos += size_to_write; 658 } 659 660 if (fdp->pos > (tee_fs_off_t)new_meta->info.length) 661 new_meta->info.length = fdp->pos; 662 663 return TEE_SUCCESS; 664 failed: 665 fdp->pos = orig_pos; 666 return TEE_ERROR_GENERIC; 667 } 668 669 static TEE_Result open_internal(const char *file, bool create, bool overwrite, 670 struct tee_file_handle **fh) 671 { 672 TEE_Result res; 673 size_t len; 674 struct tee_fs_fd *fdp = NULL; 675 676 if (!file) 677 return TEE_ERROR_BAD_PARAMETERS; 678 679 len = strlen(file) + 1; 680 if (len > TEE_FS_NAME_MAX) 681 return TEE_ERROR_BAD_PARAMETERS; 682 683 fdp = calloc(1, sizeof(struct tee_fs_fd)); 684 if (!fdp) 685 return TEE_ERROR_OUT_OF_MEMORY; 686 fdp->fd = -1; 687 688 mutex_lock(&ree_fs_mutex); 689 690 /* init internal status */ 691 if (init_block_cache(&fdp->block_cache)) { 692 res = TEE_ERROR_OUT_OF_MEMORY; 693 goto exit_free_fd; 694 } 695 696 res = read_meta(fdp, file); 697 if (res == TEE_SUCCESS) { 698 if (overwrite) { 699 res = TEE_ERROR_ACCESS_CONFLICT; 700 goto exit_close_file; 701 } 702 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 703 if (!create) 704 goto exit_destroy_block_cache; 705 res = create_meta(fdp, file); 706 if (res != TEE_SUCCESS) 707 goto exit_close_file; 708 } else { 709 goto exit_destroy_block_cache; 710 } 711 712 *fh = (struct tee_file_handle *)fdp; 713 goto exit; 714 715 exit_close_file: 716 if (fdp->fd != -1) 717 tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 718 if (create) 719 tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, file); 720 exit_destroy_block_cache: 721 destroy_block_cache(&fdp->block_cache); 722 exit_free_fd: 723 free(fdp); 724 exit: 725 mutex_unlock(&ree_fs_mutex); 726 return res; 727 } 728 729 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh) 730 { 731 return open_internal(file, false, false, fh); 732 } 733 734 static TEE_Result ree_fs_create(const char *file, bool overwrite, 735 struct tee_file_handle **fh) 736 { 737 return open_internal(file, true, overwrite, fh); 738 } 739 740 static void ree_fs_close(struct tee_file_handle **fh) 741 { 742 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 743 744 if (fdp) { 745 destroy_block_cache(&fdp->block_cache); 746 tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 747 free(fdp); 748 *fh = NULL; 749 } 750 } 751 752 static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset, 753 TEE_Whence whence, int32_t *new_offs) 754 { 755 TEE_Result res; 756 tee_fs_off_t new_pos; 757 size_t filelen; 758 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 759 760 mutex_lock(&ree_fs_mutex); 761 762 DMSG("offset=%d, whence=%d", (int)offset, whence); 763 764 filelen = fdp->meta.info.length; 765 766 switch (whence) { 767 case TEE_DATA_SEEK_SET: 768 new_pos = offset; 769 break; 770 771 case TEE_DATA_SEEK_CUR: 772 new_pos = fdp->pos + offset; 773 break; 774 775 case TEE_DATA_SEEK_END: 776 new_pos = filelen + offset; 777 break; 778 779 default: 780 res = TEE_ERROR_BAD_PARAMETERS; 781 goto exit; 782 } 783 784 if (new_pos < 0) 785 new_pos = 0; 786 787 if (new_pos > TEE_DATA_MAX_POSITION) { 788 EMSG("Position is beyond TEE_DATA_MAX_POSITION"); 789 res = TEE_ERROR_BAD_PARAMETERS; 790 goto exit; 791 } 792 793 fdp->pos = new_pos; 794 if (new_offs) 795 *new_offs = new_pos; 796 res = TEE_SUCCESS; 797 exit: 798 mutex_unlock(&ree_fs_mutex); 799 return res; 800 } 801 802 /* 803 * To ensure atomic truncate operation, we can: 804 * 805 * - update file length to new length 806 * - commit new meta 807 * 808 * To ensure atomic extend operation, we can: 809 * 810 * - update file length to new length 811 * - allocate and fill zero data to new blocks 812 * - commit new meta 813 * 814 * Any failure before committing new meta is considered as 815 * update failed, and the file content will not be updated 816 */ 817 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, 818 tee_fs_off_t new_file_len) 819 { 820 TEE_Result res; 821 size_t old_file_len = fdp->meta.info.length; 822 struct tee_fs_file_meta new_meta; 823 824 if ((size_t)new_file_len == old_file_len) { 825 DMSG("Ignore due to file length does not changed"); 826 return TEE_SUCCESS; 827 } 828 829 if (new_file_len > MAX_FILE_SIZE) { 830 EMSG("Over maximum file size(%d)", MAX_FILE_SIZE); 831 return TEE_ERROR_BAD_PARAMETERS; 832 } 833 834 new_meta = fdp->meta; 835 new_meta.info.length = new_file_len; 836 837 if ((size_t)new_file_len < old_file_len) { 838 DMSG("Truncate file length to %zu", (size_t)new_file_len); 839 840 res = commit_meta_file(fdp, &new_meta); 841 if (res != TEE_SUCCESS) 842 return res; 843 } else { 844 size_t ext_len = new_file_len - old_file_len; 845 int orig_pos = fdp->pos; 846 uint8_t *buf; 847 848 buf = calloc(1, BLOCK_FILE_SIZE); 849 if (!buf) { 850 EMSG("Failed to allocate buffer, size=%d", 851 BLOCK_FILE_SIZE); 852 return TEE_ERROR_OUT_OF_MEMORY; 853 } 854 855 DMSG("Extend file length to %zu", (size_t)new_file_len); 856 857 fdp->pos = old_file_len; 858 859 res = TEE_SUCCESS; 860 while (ext_len > 0) { 861 size_t data_len = (ext_len > BLOCK_FILE_SIZE) ? 862 BLOCK_FILE_SIZE : ext_len; 863 864 DMSG("fill len=%zu", data_len); 865 res = out_of_place_write(fdp, buf, data_len, &new_meta); 866 if (res != TEE_SUCCESS) { 867 EMSG("Failed to fill data"); 868 break; 869 } 870 871 ext_len -= data_len; 872 } 873 874 free(buf); 875 fdp->pos = orig_pos; 876 877 if (res == TEE_SUCCESS) { 878 res = commit_meta_file(fdp, &new_meta); 879 if (res != TEE_SUCCESS) 880 EMSG("Failed to commit meta file"); 881 } 882 } 883 884 return res; 885 } 886 887 static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf, 888 size_t *len) 889 { 890 TEE_Result res; 891 int start_block_num; 892 int end_block_num; 893 size_t remain_bytes; 894 uint8_t *data_ptr = buf; 895 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 896 897 mutex_lock(&ree_fs_mutex); 898 899 remain_bytes = *len; 900 if ((fdp->pos + remain_bytes) < remain_bytes || 901 fdp->pos > (tee_fs_off_t)fdp->meta.info.length) 902 remain_bytes = 0; 903 else if (fdp->pos + remain_bytes > fdp->meta.info.length) 904 remain_bytes = fdp->meta.info.length - fdp->pos; 905 906 *len = remain_bytes; 907 908 if (!remain_bytes) { 909 res = TEE_SUCCESS; 910 goto exit; 911 } 912 913 start_block_num = pos_to_block_num(fdp->pos); 914 end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1); 915 916 while (start_block_num <= end_block_num) { 917 struct block *b; 918 int offset = fdp->pos % BLOCK_FILE_SIZE; 919 size_t size_to_read = remain_bytes > BLOCK_FILE_SIZE ? 920 BLOCK_FILE_SIZE : remain_bytes; 921 922 if (size_to_read + offset > BLOCK_FILE_SIZE) 923 size_to_read = BLOCK_FILE_SIZE - offset; 924 925 b = block_ops.read(fdp, start_block_num); 926 if (!b) { 927 res = TEE_ERROR_CORRUPT_OBJECT; 928 goto exit; 929 } 930 931 read_data_from_block(b, offset, data_ptr, size_to_read); 932 data_ptr += size_to_read; 933 remain_bytes -= size_to_read; 934 fdp->pos += size_to_read; 935 936 start_block_num++; 937 } 938 res = TEE_SUCCESS; 939 exit: 940 mutex_unlock(&ree_fs_mutex); 941 return res; 942 } 943 944 /* 945 * To ensure atomicity of write operation, we need to 946 * do the following steps: 947 * (The sequence of operations is very important) 948 * 949 * - Create a new backup version of meta file as a copy 950 * of current meta file. 951 * - For each blocks to write: 952 * - Create new backup version for current block. 953 * - Write data to new backup version. 954 * - Update the new meta file accordingly. 955 * - Write the new meta file. 956 * 957 * (Any failure in above steps is considered as update failed, 958 * and the file content will not be updated) 959 */ 960 static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf, 961 size_t len) 962 { 963 TEE_Result res; 964 struct tee_fs_file_meta new_meta; 965 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 966 size_t file_size; 967 968 969 if (!len) 970 return TEE_SUCCESS; 971 972 mutex_lock(&ree_fs_mutex); 973 974 file_size = fdp->meta.info.length; 975 976 if ((fdp->pos + len) > MAX_FILE_SIZE || (fdp->pos + len) < len) { 977 res = TEE_ERROR_BAD_PARAMETERS; 978 goto exit; 979 } 980 981 if (file_size < (size_t)fdp->pos) { 982 res = ree_fs_ftruncate_internal(fdp, fdp->pos); 983 if (res != TEE_SUCCESS) 984 goto exit; 985 } 986 987 new_meta = fdp->meta; 988 res = out_of_place_write(fdp, buf, len, &new_meta); 989 if (res != TEE_SUCCESS) 990 goto exit; 991 992 res = commit_meta_file(fdp, &new_meta); 993 exit: 994 mutex_unlock(&ree_fs_mutex); 995 return res; 996 } 997 998 static TEE_Result ree_fs_rename_internal(const char *old, const char *new, 999 bool overwrite) 1000 { 1001 size_t old_len; 1002 size_t new_len; 1003 1004 DMSG("old=%s, new=%s", old, new); 1005 1006 old_len = strlen(old) + 1; 1007 new_len = strlen(new) + 1; 1008 1009 if (old_len > TEE_FS_NAME_MAX || new_len > TEE_FS_NAME_MAX) 1010 return TEE_ERROR_BAD_PARAMETERS; 1011 1012 return tee_fs_rpc_new_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite); 1013 } 1014 1015 static TEE_Result ree_fs_rename(const char *old, const char *new, 1016 bool overwrite) 1017 { 1018 TEE_Result res; 1019 1020 mutex_lock(&ree_fs_mutex); 1021 res = ree_fs_rename_internal(old, new, overwrite); 1022 mutex_unlock(&ree_fs_mutex); 1023 1024 return res; 1025 } 1026 1027 static TEE_Result ree_fs_remove(const char *file) 1028 { 1029 TEE_Result res; 1030 1031 mutex_lock(&ree_fs_mutex); 1032 res = tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, file); 1033 mutex_unlock(&ree_fs_mutex); 1034 1035 return res; 1036 } 1037 1038 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 1039 { 1040 TEE_Result res; 1041 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 1042 1043 mutex_lock(&ree_fs_mutex); 1044 res = ree_fs_ftruncate_internal(fdp, len); 1045 mutex_unlock(&ree_fs_mutex); 1046 1047 return res; 1048 } 1049 1050 const struct tee_file_operations ree_fs_ops = { 1051 .open = ree_fs_open, 1052 .create = ree_fs_create, 1053 .close = ree_fs_close, 1054 .read = ree_fs_read, 1055 .write = ree_fs_write, 1056 .seek = ree_fs_seek, 1057 .truncate = ree_fs_truncate, 1058 .rename = ree_fs_rename, 1059 .remove = ree_fs_remove, 1060 .opendir = ree_fs_opendir_rpc, 1061 .closedir = ree_fs_closedir_rpc, 1062 .readdir = ree_fs_readdir_rpc, 1063 }; 1064