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