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