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