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