1 /* 2 * Copyright (c) 2014, STMicroelectronics International N.V. 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 <kernel/tee_common.h> 29 #include <kernel/handle.h> 30 #include <tee/tee_rpmb_fs.h> 31 #include <tee/tee_rpmb.h> 32 #include <tee/tee_fs_defs.h> 33 #include <tee/tee_fs.h> 34 #include <tee/tee_fs_key_manager.h> 35 #include <mm/tee_mm.h> 36 #include <trace.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <string_ext.h> 40 #include <util.h> 41 #include <sys/queue.h> 42 43 #ifdef CFG_ENC_FS 44 #include <tee/tee_cryp_provider.h> 45 #endif 46 47 #include "tee_fs_private.h" 48 49 #define RPMB_STORAGE_START_ADDRESS 0 50 #define RPMB_FS_FAT_START_ADDRESS 512 51 #define RPMB_BLOCK_SIZE_SHIFT 8 52 53 #define RPMB_FS_MAGIC 0x52504D42 54 #define FS_VERSION 2 55 #define N_ENTRIES 8 56 57 #define FILE_IS_ACTIVE (1u << 0) 58 #define FILE_IS_LAST_ENTRY (1u << 1) 59 60 /** 61 * FS parameters: Information often used by internal functions. 62 * fat_start_address will be set by rpmb_fs_setup(). 63 * rpmb_fs_parameters can be read by any other function. 64 */ 65 struct rpmb_fs_parameters { 66 uint32_t fat_start_address; 67 uint32_t max_rpmb_address; 68 }; 69 70 /** 71 * File entry for a single file in a RPMB_FS partition. 72 */ 73 struct rpmb_fat_entry { 74 uint32_t start_address; 75 uint32_t data_size; 76 uint32_t flags; 77 uint32_t write_counter; 78 uint8_t fek[TEE_FS_KM_FEK_SIZE]; 79 char filename[TEE_RPMB_FS_FILENAME_LENGTH]; 80 }; 81 82 /** 83 * FAT entry context with reference to a FAT entry and its 84 * location in RPMB. 85 */ 86 struct rpmb_file_handle { 87 /* Pointer to a fat_entry */ 88 struct rpmb_fat_entry fat_entry; 89 /* Pointer to a filename */ 90 char filename[TEE_RPMB_FS_FILENAME_LENGTH]; 91 /* Adress for current entry in RPMB */ 92 uint32_t rpmb_fat_address; 93 /* Current position */ 94 uint32_t pos; 95 }; 96 97 /** 98 * RPMB_FS partition data 99 */ 100 struct rpmb_fs_partition { 101 uint32_t rpmb_fs_magic; 102 uint32_t fs_version; 103 uint32_t write_counter; 104 uint32_t fat_start_address; 105 /* Do not use reserved[] for other purpose than partition data. */ 106 uint8_t reserved[112]; 107 }; 108 109 /** 110 * A node in a list of directory entries. entry->name is a 111 * pointer to name here. 112 */ 113 struct tee_rpmb_fs_dirent { 114 struct tee_fs_dirent entry; 115 char name[TEE_RPMB_FS_FILENAME_LENGTH]; 116 SIMPLEQ_ENTRY(tee_rpmb_fs_dirent) link; 117 }; 118 119 /** 120 * The RPMB directory representation. It contains a queue of 121 * RPMB directory entries: 'next'. 122 * The current pointer points to the last directory entry 123 * returned by readdir(). 124 */ 125 struct tee_fs_dir { 126 struct tee_rpmb_fs_dirent *current; 127 SIMPLEQ_HEAD(next_head, tee_rpmb_fs_dirent) next; 128 }; 129 130 static TEE_Result get_fat_start_address(uint32_t *addr); 131 132 static struct rpmb_fs_parameters *fs_par; 133 134 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER; 135 136 static void dump_fat(void) 137 { 138 TEE_Result res = TEE_ERROR_GENERIC; 139 struct rpmb_fat_entry *fat_entries = NULL; 140 uint32_t fat_address; 141 size_t size; 142 int i; 143 bool last_entry_found = false; 144 145 res = get_fat_start_address(&fat_address); 146 if (res != TEE_SUCCESS) 147 goto out; 148 149 size = N_ENTRIES * sizeof(struct rpmb_fat_entry); 150 fat_entries = malloc(size); 151 if (!fat_entries) { 152 res = TEE_ERROR_OUT_OF_MEMORY; 153 goto out; 154 } 155 156 while (!last_entry_found) { 157 res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address, 158 (uint8_t *)fat_entries, size, NULL); 159 if (res != TEE_SUCCESS) 160 goto out; 161 162 for (i = 0; i < N_ENTRIES; i++) { 163 164 FMSG("flags 0x%x, size %d, address 0x%x, filename '%s'", 165 fat_entries[i].flags, 166 fat_entries[i].data_size, 167 fat_entries[i].start_address, 168 fat_entries[i].filename); 169 170 if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) { 171 last_entry_found = true; 172 break; 173 } 174 175 /* Move to next fat_entry. */ 176 fat_address += sizeof(struct rpmb_fat_entry); 177 } 178 } 179 180 out: 181 free(fat_entries); 182 } 183 184 #if (TRACE_LEVEL >= TRACE_DEBUG) 185 static void dump_fh(struct rpmb_file_handle *fh) 186 { 187 DMSG("fh->filename=%s", fh->filename); 188 DMSG("fh->pos=%u", fh->pos); 189 DMSG("fh->rpmb_fat_address=%u", fh->rpmb_fat_address); 190 DMSG("fh->fat_entry.start_address=%u", fh->fat_entry.start_address); 191 DMSG("fh->fat_entry.data_size=%u", fh->fat_entry.data_size); 192 } 193 #else 194 static void dump_fh(struct rpmb_file_handle *fh __unused) 195 { 196 } 197 #endif 198 199 static struct rpmb_file_handle *alloc_file_handle(const char *filename) 200 { 201 struct rpmb_file_handle *fh = NULL; 202 203 fh = calloc(1, sizeof(struct rpmb_file_handle)); 204 if (!fh) 205 return NULL; 206 207 if (filename) 208 strlcpy(fh->filename, filename, sizeof(fh->filename)); 209 210 return fh; 211 } 212 213 /** 214 * write_fat_entry: Store info in a fat_entry to RPMB. 215 */ 216 static TEE_Result write_fat_entry(struct rpmb_file_handle *fh, 217 bool update_write_counter) 218 { 219 TEE_Result res = TEE_ERROR_GENERIC; 220 221 /* Protect partition data. */ 222 if (fh->rpmb_fat_address < sizeof(struct rpmb_fs_partition)) { 223 res = TEE_ERROR_ACCESS_CONFLICT; 224 goto out; 225 } 226 227 if (fh->rpmb_fat_address % sizeof(struct rpmb_fat_entry) != 0) { 228 res = TEE_ERROR_BAD_PARAMETERS; 229 goto out; 230 } 231 232 if (update_write_counter) { 233 res = tee_rpmb_get_write_counter(CFG_RPMB_FS_DEV_ID, 234 &fh->fat_entry.write_counter); 235 if (res != TEE_SUCCESS) 236 goto out; 237 } 238 239 res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, fh->rpmb_fat_address, 240 (uint8_t *)&fh->fat_entry, 241 sizeof(struct rpmb_fat_entry), NULL); 242 243 dump_fat(); 244 245 out: 246 return res; 247 } 248 249 /** 250 * rpmb_fs_setup: Setup rpmb fs. 251 * Set initial partition and FS values and write to RPMB. 252 * Store frequently used data in RAM. 253 */ 254 static TEE_Result rpmb_fs_setup(void) 255 { 256 TEE_Result res = TEE_ERROR_GENERIC; 257 struct rpmb_fs_partition *partition_data = NULL; 258 struct rpmb_file_handle *fh = NULL; 259 uint32_t max_rpmb_block = 0; 260 261 if (fs_par) { 262 res = TEE_SUCCESS; 263 goto out; 264 } 265 266 res = tee_rpmb_get_max_block(CFG_RPMB_FS_DEV_ID, &max_rpmb_block); 267 if (res != TEE_SUCCESS) 268 goto out; 269 270 partition_data = calloc(1, sizeof(struct rpmb_fs_partition)); 271 if (!partition_data) { 272 res = TEE_ERROR_OUT_OF_MEMORY; 273 goto out; 274 } 275 276 res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS, 277 (uint8_t *)partition_data, 278 sizeof(struct rpmb_fs_partition), NULL); 279 if (res != TEE_SUCCESS) 280 goto out; 281 282 #ifndef CFG_RPMB_RESET_FAT 283 if (partition_data->rpmb_fs_magic == RPMB_FS_MAGIC) { 284 if (partition_data->fs_version == FS_VERSION) { 285 res = TEE_SUCCESS; 286 goto store_fs_par; 287 } else { 288 /* Wrong software is in use. */ 289 res = TEE_ERROR_ACCESS_DENIED; 290 goto out; 291 } 292 } 293 #else 294 EMSG("**** Clearing Storage ****"); 295 #endif 296 297 /* Setup new partition data. */ 298 partition_data->rpmb_fs_magic = RPMB_FS_MAGIC; 299 partition_data->fs_version = FS_VERSION; 300 partition_data->fat_start_address = RPMB_FS_FAT_START_ADDRESS; 301 302 /* Initial FAT entry with FILE_IS_LAST_ENTRY flag set. */ 303 fh = alloc_file_handle(NULL); 304 if (!fh) { 305 res = TEE_ERROR_OUT_OF_MEMORY; 306 goto out; 307 } 308 fh->fat_entry.flags = FILE_IS_LAST_ENTRY; 309 fh->rpmb_fat_address = partition_data->fat_start_address; 310 311 /* Write init FAT entry and partition data to RPMB. */ 312 res = write_fat_entry(fh, true); 313 if (res != TEE_SUCCESS) 314 goto out; 315 316 res = 317 tee_rpmb_get_write_counter(CFG_RPMB_FS_DEV_ID, 318 &partition_data->write_counter); 319 if (res != TEE_SUCCESS) 320 goto out; 321 res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS, 322 (uint8_t *)partition_data, 323 sizeof(struct rpmb_fs_partition), NULL); 324 325 #ifndef CFG_RPMB_RESET_FAT 326 store_fs_par: 327 #endif 328 329 /* Store FAT start address. */ 330 fs_par = calloc(1, sizeof(struct rpmb_fs_parameters)); 331 if (!fs_par) { 332 res = TEE_ERROR_OUT_OF_MEMORY; 333 goto out; 334 } 335 336 fs_par->fat_start_address = partition_data->fat_start_address; 337 fs_par->max_rpmb_address = max_rpmb_block << RPMB_BLOCK_SIZE_SHIFT; 338 339 dump_fat(); 340 341 out: 342 free(fh); 343 free(partition_data); 344 return res; 345 } 346 347 /** 348 * get_fat_start_address: 349 * FAT start_address from fs_par. 350 */ 351 static TEE_Result get_fat_start_address(uint32_t *addr) 352 { 353 if (!fs_par) 354 return TEE_ERROR_NO_DATA; 355 356 *addr = fs_par->fat_start_address; 357 358 return TEE_SUCCESS; 359 } 360 361 /** 362 * read_fat: Read FAT entries 363 * Return matching FAT entry for read, rm rename and stat. 364 * Build up memory pool and return matching entry for write operation. 365 * "Last FAT entry" can be returned during write. 366 */ 367 static TEE_Result read_fat(struct rpmb_file_handle *fh, tee_mm_pool_t *p) 368 { 369 TEE_Result res = TEE_ERROR_GENERIC; 370 tee_mm_entry_t *mm = NULL; 371 struct rpmb_fat_entry *fat_entries = NULL; 372 uint32_t fat_address; 373 size_t size; 374 int i; 375 bool entry_found = false; 376 bool last_entry_found = false; 377 bool expand_fat = false; 378 struct rpmb_file_handle last_fh; 379 380 DMSG("fat_address %d", fh->rpmb_fat_address); 381 382 res = rpmb_fs_setup(); 383 if (res != TEE_SUCCESS) 384 goto out; 385 386 res = get_fat_start_address(&fat_address); 387 if (res != TEE_SUCCESS) 388 goto out; 389 390 size = N_ENTRIES * sizeof(struct rpmb_fat_entry); 391 fat_entries = malloc(size); 392 if (!fat_entries) { 393 res = TEE_ERROR_OUT_OF_MEMORY; 394 goto out; 395 } 396 397 /* 398 * The pool is used to represent the current RPMB layout. To find 399 * a slot for the file tee_mm_alloc is called on the pool. Thus 400 * if it is not NULL the entire FAT must be traversed to fill in 401 * the pool. 402 */ 403 while (!last_entry_found && (!entry_found || p)) { 404 res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address, 405 (uint8_t *)fat_entries, size, NULL); 406 if (res != TEE_SUCCESS) 407 goto out; 408 409 for (i = 0; i < N_ENTRIES; i++) { 410 /* 411 * Look for an entry, matching filenames. (read, rm, 412 * rename and stat.). Only store first filename match. 413 */ 414 if (fh->filename && 415 (strcmp(fh->filename, 416 fat_entries[i].filename) == 0) && 417 (fat_entries[i].flags & FILE_IS_ACTIVE) && 418 (!entry_found)) { 419 entry_found = true; 420 fh->rpmb_fat_address = fat_address; 421 memcpy(&fh->fat_entry, &fat_entries[i], 422 sizeof(struct rpmb_fat_entry)); 423 if (!p) 424 break; 425 } 426 427 /* Add existing files to memory pool. (write) */ 428 if (p) { 429 if ((fat_entries[i].flags & FILE_IS_ACTIVE) && 430 (fat_entries[i].data_size > 0)) { 431 432 mm = tee_mm_alloc2 433 (p, 434 fat_entries[i].start_address, 435 fat_entries[i].data_size); 436 if (!mm) { 437 res = TEE_ERROR_OUT_OF_MEMORY; 438 goto out; 439 } 440 } 441 442 /* Unused FAT entries can be reused (write) */ 443 if (((fat_entries[i].flags & FILE_IS_ACTIVE) == 444 0) && (fh->rpmb_fat_address == 0)) { 445 fh->rpmb_fat_address = fat_address; 446 memcpy(&fh->fat_entry, &fat_entries[i], 447 sizeof(struct rpmb_fat_entry)); 448 } 449 } 450 451 if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) { 452 last_entry_found = true; 453 454 /* 455 * If the last entry was reached and was chosen 456 * by the previous check, then the FAT needs to 457 * be expanded. 458 * fh->rpmb_fat_address is the address chosen 459 * to store the files FAT entry and fat_address 460 * is the current FAT entry address being 461 * compared. 462 */ 463 if (p && fh->rpmb_fat_address == fat_address) 464 expand_fat = true; 465 break; 466 } 467 468 /* Move to next fat_entry. */ 469 fat_address += sizeof(struct rpmb_fat_entry); 470 } 471 } 472 473 /* 474 * Represent the FAT table in the pool. 475 */ 476 if (p) { 477 /* 478 * Since fat_address is the start of the last entry it needs to 479 * be moved up by an entry. 480 */ 481 fat_address += sizeof(struct rpmb_fat_entry); 482 483 /* Make room for yet a FAT entry and add to memory pool. */ 484 if (expand_fat) 485 fat_address += sizeof(struct rpmb_fat_entry); 486 487 mm = tee_mm_alloc2(p, RPMB_STORAGE_START_ADDRESS, fat_address); 488 if (!mm) { 489 res = TEE_ERROR_OUT_OF_MEMORY; 490 goto out; 491 } 492 493 if (expand_fat) { 494 /* 495 * Point fat_address to the beginning of the new 496 * entry. 497 */ 498 fat_address -= sizeof(struct rpmb_fat_entry); 499 memset(&last_fh, 0, sizeof(last_fh)); 500 last_fh.fat_entry.flags = FILE_IS_LAST_ENTRY; 501 last_fh.rpmb_fat_address = fat_address; 502 res = write_fat_entry(&last_fh, true); 503 if (res != TEE_SUCCESS) 504 goto out; 505 } 506 } 507 508 if (fh->filename && !fh->rpmb_fat_address) 509 res = TEE_ERROR_FILE_NOT_FOUND; 510 511 out: 512 free(fat_entries); 513 return res; 514 } 515 516 #ifdef CFG_ENC_FS 517 static bool is_zero(const uint8_t *buf, size_t size) 518 { 519 size_t i; 520 521 for (i = 0; i < size; i++) 522 if (buf[i]) 523 return false; 524 return true; 525 } 526 527 static TEE_Result generate_fek(struct rpmb_fat_entry *fe) 528 { 529 TEE_Result res; 530 531 again: 532 res = crypto_ops.prng.read(fe->fek, sizeof(fe->fek)); 533 if (res != TEE_SUCCESS) 534 return res; 535 536 if (is_zero(fe->fek, sizeof(fe->fek))) 537 goto again; 538 539 return res; 540 } 541 #else 542 static TEE_Result generate_fek(struct rpmb_fat_entry *fe) 543 { 544 memset(fe->fek, 0, sizeof(fe->fek)); 545 return TEE_SUCCESS; 546 } 547 #endif 548 549 int tee_rpmb_fs_open(const char *file, int flags, ...) 550 { 551 int fd = -1; 552 struct rpmb_file_handle *fh = NULL; 553 size_t filelen; 554 tee_mm_pool_t p; 555 bool pool_result; 556 TEE_Result res = TEE_ERROR_GENERIC; 557 558 if (!file) { 559 res = TEE_ERROR_BAD_PARAMETERS; 560 goto out; 561 } 562 563 filelen = strlen(file); 564 if (filelen >= TEE_RPMB_FS_FILENAME_LENGTH - 1 || filelen == 0) { 565 res = TEE_ERROR_BAD_PARAMETERS; 566 goto out; 567 } 568 569 if (file[filelen - 1] == '/') { 570 res = TEE_ERROR_BAD_PARAMETERS; 571 goto out; 572 } 573 574 fh = alloc_file_handle(file); 575 if (!fh) { 576 res = TEE_ERROR_OUT_OF_MEMORY; 577 goto out; 578 } 579 580 /* We need to do setup in order to make sure fs_par is filled in */ 581 res = rpmb_fs_setup(); 582 if (res != TEE_SUCCESS) 583 goto out; 584 585 if (flags & TEE_FS_O_CREATE) { 586 /* Upper memory allocation must be used for RPMB_FS. */ 587 pool_result = tee_mm_init(&p, 588 RPMB_STORAGE_START_ADDRESS, 589 fs_par->max_rpmb_address, 590 RPMB_BLOCK_SIZE_SHIFT, 591 TEE_MM_POOL_HI_ALLOC); 592 593 if (!pool_result) { 594 res = TEE_ERROR_OUT_OF_MEMORY; 595 goto out; 596 } 597 598 res = read_fat(fh, &p); 599 tee_mm_final(&p); 600 if (res != TEE_SUCCESS) 601 goto out; 602 } else { 603 res = read_fat(fh, NULL); 604 if (res != TEE_SUCCESS) 605 goto out; 606 } 607 608 /* Add the handle to the db */ 609 fd = handle_get(&fs_handle_db, fh); 610 if (fd == -1) { 611 res = TEE_ERROR_OUT_OF_MEMORY; 612 goto out; 613 } 614 615 /* 616 * If this is opened with create and the entry found was not active 617 * then this is a new file and the FAT entry must be written 618 */ 619 if (flags & TEE_FS_O_CREATE) { 620 if ((fh->fat_entry.flags & FILE_IS_ACTIVE) == 0) { 621 memset(&fh->fat_entry, 0, 622 sizeof(struct rpmb_fat_entry)); 623 memcpy(fh->fat_entry.filename, file, strlen(file)); 624 /* Start address and size are 0 */ 625 fh->fat_entry.flags = FILE_IS_ACTIVE; 626 627 res = generate_fek(&fh->fat_entry); 628 if (res != TEE_SUCCESS) { 629 handle_put(&fs_handle_db, fd); 630 fd = -1; 631 goto out; 632 } 633 DMSG("GENERATE FEK key: %p", 634 (void *)fh->fat_entry.fek); 635 DHEXDUMP(fh->fat_entry.fek, sizeof(fh->fat_entry.fek)); 636 637 res = write_fat_entry(fh, true); 638 if (res != TEE_SUCCESS) { 639 handle_put(&fs_handle_db, fd); 640 fd = -1; 641 goto out; 642 } 643 } 644 } 645 646 res = TEE_SUCCESS; 647 648 out: 649 if (res != TEE_SUCCESS) { 650 if (fh) 651 free(fh); 652 653 fd = -1; 654 } 655 656 return fd; 657 } 658 659 int tee_rpmb_fs_close(int fd) 660 { 661 struct rpmb_file_handle *fh; 662 663 fh = handle_put(&fs_handle_db, fd); 664 if (fh) { 665 free(fh); 666 return 0; 667 } 668 669 return -1; 670 } 671 672 int tee_rpmb_fs_read(int fd, uint8_t *buf, size_t size) 673 { 674 TEE_Result res = TEE_ERROR_GENERIC; 675 struct rpmb_file_handle *fh; 676 int read_size = -1; 677 678 if (!size) 679 return 0; 680 681 if (!buf) { 682 res = TEE_ERROR_BAD_PARAMETERS; 683 goto out; 684 } 685 686 fh = handle_lookup(&fs_handle_db, fd); 687 if (!fh) { 688 res = TEE_ERROR_BAD_PARAMETERS; 689 goto out; 690 } 691 dump_fh(fh); 692 693 res = read_fat(fh, NULL); 694 if (res != TEE_SUCCESS) 695 goto out; 696 697 size = MIN(size, fh->fat_entry.data_size - fh->pos); 698 if (size > 0) { 699 res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, 700 fh->fat_entry.start_address + fh->pos, buf, 701 size, fh->fat_entry.fek); 702 if (res != TEE_SUCCESS) 703 goto out; 704 } 705 706 read_size = size; 707 res = TEE_SUCCESS; 708 709 out: 710 if (res != TEE_SUCCESS) 711 read_size = -1; 712 713 return read_size; 714 } 715 716 int tee_rpmb_fs_write(int fd, uint8_t *buf, size_t size) 717 { 718 TEE_Result res = TEE_ERROR_GENERIC; 719 struct rpmb_file_handle *fh; 720 tee_mm_pool_t p; 721 bool pool_result = false; 722 tee_mm_entry_t *mm; 723 size_t end; 724 size_t newsize; 725 uint8_t *newbuf = NULL; 726 uintptr_t newaddr; 727 uint32_t start_addr; 728 729 if (!size) 730 return 0; 731 732 if (!buf) { 733 res = TEE_ERROR_BAD_PARAMETERS; 734 goto out; 735 } 736 737 if (!fs_par) { 738 res = TEE_ERROR_GENERIC; 739 goto out; 740 } 741 742 fh = handle_lookup(&fs_handle_db, fd); 743 if (!fh) { 744 res = TEE_ERROR_BAD_PARAMETERS; 745 goto out; 746 } 747 dump_fh(fh); 748 749 /* Upper memory allocation must be used for RPMB_FS. */ 750 pool_result = tee_mm_init(&p, 751 RPMB_STORAGE_START_ADDRESS, 752 fs_par->max_rpmb_address, 753 RPMB_BLOCK_SIZE_SHIFT, 754 TEE_MM_POOL_HI_ALLOC); 755 if (!pool_result) { 756 res = TEE_ERROR_OUT_OF_MEMORY; 757 goto out; 758 } 759 760 res = read_fat(fh, &p); 761 if (res != TEE_SUCCESS) 762 goto out; 763 764 TEE_ASSERT(!(fh->fat_entry.flags & FILE_IS_LAST_ENTRY)); 765 766 end = fh->pos + size; 767 start_addr = fh->fat_entry.start_address + fh->pos; 768 769 if (end <= fh->fat_entry.data_size && 770 tee_rpmb_write_is_atomic(CFG_RPMB_FS_DEV_ID, start_addr, size)) { 771 772 DMSG("Updating data in-place"); 773 res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, start_addr, buf, 774 size, fh->fat_entry.fek); 775 if (res != TEE_SUCCESS) 776 goto out; 777 } else { 778 /* 779 * File must be extended, or update cannot be atomic: allocate, 780 * read, update, write. 781 */ 782 783 DMSG("Need to re-allocate"); 784 newsize = MAX(end, fh->fat_entry.data_size); 785 mm = tee_mm_alloc(&p, newsize); 786 newbuf = calloc(newsize, 1); 787 if (!mm || !newbuf) { 788 res = TEE_ERROR_OUT_OF_MEMORY; 789 goto out; 790 } 791 792 if (fh->fat_entry.data_size) { 793 res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, 794 fh->fat_entry.start_address, 795 newbuf, fh->fat_entry.data_size, 796 fh->fat_entry.fek); 797 if (res != TEE_SUCCESS) 798 goto out; 799 } 800 801 memcpy(newbuf + fh->pos, buf, size); 802 803 newaddr = tee_mm_get_smem(mm); 804 res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, newaddr, newbuf, 805 newsize, fh->fat_entry.fek); 806 if (res != TEE_SUCCESS) 807 goto out; 808 809 fh->fat_entry.data_size = newsize; 810 fh->fat_entry.start_address = newaddr; 811 res = write_fat_entry(fh, true); 812 if (res != TEE_SUCCESS) 813 goto out; 814 } 815 816 fh->pos += size; 817 out: 818 if (pool_result) 819 tee_mm_final(&p); 820 if (newbuf) 821 free(newbuf); 822 823 if (res == TEE_SUCCESS) 824 return size; 825 826 return -1; 827 } 828 829 tee_fs_off_t tee_rpmb_fs_lseek(int fd, tee_fs_off_t offset, int whence) 830 { 831 struct rpmb_file_handle *fh; 832 TEE_Result res; 833 tee_fs_off_t ret = -1; 834 tee_fs_off_t new_pos; 835 836 fh = handle_lookup(&fs_handle_db, fd); 837 if (!fh) 838 return TEE_ERROR_BAD_PARAMETERS; 839 840 res = read_fat(fh, NULL); 841 if (res != TEE_SUCCESS) 842 return -1; 843 844 switch (whence) { 845 case TEE_FS_SEEK_SET: 846 new_pos = offset; 847 break; 848 849 case TEE_FS_SEEK_CUR: 850 new_pos = fh->pos + offset; 851 break; 852 853 case TEE_FS_SEEK_END: 854 new_pos = fh->fat_entry.data_size + offset; 855 break; 856 857 default: 858 goto exit; 859 } 860 861 if (new_pos < 0) 862 new_pos = 0; 863 864 if (new_pos > TEE_DATA_MAX_POSITION) { 865 EMSG("Position is beyond TEE_DATA_MAX_POSITION"); 866 goto exit; 867 } 868 869 ret = fh->pos = new_pos; 870 exit: 871 return ret; 872 } 873 874 TEE_Result tee_rpmb_fs_rm(const char *filename) 875 { 876 TEE_Result res = TEE_ERROR_GENERIC; 877 struct rpmb_file_handle *fh = NULL; 878 879 if (!filename || strlen(filename) >= TEE_RPMB_FS_FILENAME_LENGTH - 1) { 880 res = TEE_ERROR_BAD_PARAMETERS; 881 goto out; 882 } 883 884 fh = alloc_file_handle(filename); 885 if (!fh) { 886 res = TEE_ERROR_OUT_OF_MEMORY; 887 goto out; 888 } 889 890 res = read_fat(fh, NULL); 891 if (res != TEE_SUCCESS) 892 goto out; 893 894 /* Clear this file entry. */ 895 memset(&fh->fat_entry, 0, sizeof(struct rpmb_fat_entry)); 896 res = write_fat_entry(fh, false); 897 898 out: 899 free(fh); 900 return res; 901 } 902 903 TEE_Result tee_rpmb_fs_rename(const char *old_name, const char *new_name) 904 { 905 TEE_Result res = TEE_ERROR_GENERIC; 906 struct rpmb_file_handle *fh_old = NULL; 907 struct rpmb_file_handle *fh_new = NULL; 908 uint32_t old_len; 909 uint32_t new_len; 910 911 if (!old_name || !new_name) { 912 res = TEE_ERROR_BAD_PARAMETERS; 913 goto out; 914 } 915 916 old_len = strlen(old_name); 917 new_len = strlen(new_name); 918 919 if ((old_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || 920 (new_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || (new_len == 0)) { 921 922 res = TEE_ERROR_BAD_PARAMETERS; 923 goto out; 924 } 925 926 fh_old = alloc_file_handle(old_name); 927 if (!fh_old) { 928 res = TEE_ERROR_OUT_OF_MEMORY; 929 goto out; 930 } 931 932 fh_new = alloc_file_handle(new_name); 933 if (!fh_new) { 934 res = TEE_ERROR_OUT_OF_MEMORY; 935 goto out; 936 } 937 938 res = read_fat(fh_old, NULL); 939 if (res != TEE_SUCCESS) 940 goto out; 941 942 res = read_fat(fh_new, NULL); 943 if (res == TEE_SUCCESS) { 944 res = TEE_ERROR_BAD_PARAMETERS; 945 goto out; 946 } 947 948 memset(fh_old->fat_entry.filename, 0, TEE_RPMB_FS_FILENAME_LENGTH); 949 memcpy(fh_old->fat_entry.filename, new_name, new_len); 950 951 res = write_fat_entry(fh_old, false); 952 953 out: 954 free(fh_old); 955 free(fh_new); 956 957 return res; 958 } 959 960 int tee_rpmb_fs_mkdir(const char *path __unused, tee_fs_mode_t mode __unused) 961 { 962 /* 963 * FIXME: mkdir() should really create some entry in the FAT so that 964 * access() would return success when the directory exists but is 965 * empty. This does not matter for the current use cases. 966 */ 967 return 0; 968 } 969 970 int tee_rpmb_fs_ftruncate(int fd, tee_fs_off_t length) 971 { 972 struct rpmb_file_handle *fh; 973 tee_mm_pool_t p; 974 bool pool_result = false; 975 tee_mm_entry_t *mm; 976 uint32_t newsize; 977 uint8_t *newbuf = NULL; 978 uintptr_t newaddr; 979 TEE_Result res = TEE_ERROR_GENERIC; 980 981 if (length < 0 || length > INT32_MAX) { 982 res = TEE_ERROR_BAD_PARAMETERS; 983 goto out; 984 } 985 newsize = length; 986 987 fh = handle_lookup(&fs_handle_db, fd); 988 if (!fh) { 989 res = TEE_ERROR_BAD_PARAMETERS; 990 goto out; 991 } 992 993 res = read_fat(fh, NULL); 994 if (res != TEE_SUCCESS) 995 goto out; 996 997 if (newsize > fh->fat_entry.data_size) { 998 /* Extend file */ 999 1000 pool_result = tee_mm_init(&p, 1001 RPMB_STORAGE_START_ADDRESS, 1002 fs_par->max_rpmb_address, 1003 RPMB_BLOCK_SIZE_SHIFT, 1004 TEE_MM_POOL_HI_ALLOC); 1005 if (!pool_result) { 1006 res = TEE_ERROR_OUT_OF_MEMORY; 1007 goto out; 1008 } 1009 res = read_fat(fh, &p); 1010 if (res != TEE_SUCCESS) 1011 goto out; 1012 1013 mm = tee_mm_alloc(&p, newsize); 1014 newbuf = calloc(newsize, 1); 1015 if (!mm || !newbuf) { 1016 res = TEE_ERROR_OUT_OF_MEMORY; 1017 goto out; 1018 } 1019 1020 if (fh->fat_entry.data_size) { 1021 res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, 1022 fh->fat_entry.start_address, 1023 newbuf, fh->fat_entry.data_size, 1024 fh->fat_entry.fek); 1025 if (res != TEE_SUCCESS) 1026 goto out; 1027 } 1028 1029 newaddr = tee_mm_get_smem(mm); 1030 res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, newaddr, newbuf, 1031 newsize, fh->fat_entry.fek); 1032 if (res != TEE_SUCCESS) 1033 goto out; 1034 1035 } else { 1036 /* Don't change file location */ 1037 newaddr = fh->fat_entry.start_address; 1038 } 1039 1040 /* fh->pos is unchanged */ 1041 fh->fat_entry.data_size = newsize; 1042 fh->fat_entry.start_address = newaddr; 1043 res = write_fat_entry(fh, true); 1044 1045 out: 1046 if (pool_result) 1047 tee_mm_final(&p); 1048 if (newbuf) 1049 free(newbuf); 1050 1051 if (res == TEE_SUCCESS) 1052 return 0; 1053 1054 return -1; 1055 } 1056 1057 static void tee_rpmb_fs_dir_free(tee_fs_dir *dir) 1058 { 1059 struct tee_rpmb_fs_dirent *e; 1060 1061 if (!dir) 1062 return; 1063 1064 free(dir->current); 1065 1066 while ((e = SIMPLEQ_FIRST(&dir->next))) { 1067 SIMPLEQ_REMOVE_HEAD(&dir->next, link); 1068 free(e); 1069 } 1070 } 1071 1072 static TEE_Result tee_rpmb_fs_dir_populate(const char *path, tee_fs_dir *dir) 1073 { 1074 struct tee_rpmb_fs_dirent *current = NULL; 1075 struct rpmb_fat_entry *fat_entries = NULL; 1076 uint32_t fat_address; 1077 uint32_t filelen; 1078 char *filename; 1079 int i; 1080 bool last_entry_found = false; 1081 bool matched; 1082 struct tee_rpmb_fs_dirent *next = NULL; 1083 uint32_t pathlen; 1084 TEE_Result res = TEE_ERROR_GENERIC; 1085 uint32_t size; 1086 char temp; 1087 1088 res = rpmb_fs_setup(); 1089 if (res != TEE_SUCCESS) 1090 goto out; 1091 1092 res = get_fat_start_address(&fat_address); 1093 if (res != TEE_SUCCESS) 1094 goto out; 1095 1096 size = N_ENTRIES * sizeof(struct rpmb_fat_entry); 1097 fat_entries = malloc(size); 1098 if (!fat_entries) { 1099 res = TEE_ERROR_OUT_OF_MEMORY; 1100 goto out; 1101 } 1102 1103 pathlen = strlen(path); 1104 while (!last_entry_found) { 1105 res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address, 1106 (uint8_t *)fat_entries, size, NULL); 1107 if (res != TEE_SUCCESS) 1108 goto out; 1109 1110 for (i = 0; i < N_ENTRIES; i++) { 1111 filename = fat_entries[i].filename; 1112 if (fat_entries[i].flags & FILE_IS_ACTIVE) { 1113 matched = false; 1114 filelen = strlen(filename); 1115 if (filelen > pathlen) { 1116 temp = filename[pathlen]; 1117 filename[pathlen] = '\0'; 1118 if (strcmp(filename, path) == 0) 1119 matched = true; 1120 1121 filename[pathlen] = temp; 1122 } 1123 1124 if (matched) { 1125 next = malloc(sizeof(*next)); 1126 if (!next) { 1127 res = TEE_ERROR_OUT_OF_MEMORY; 1128 goto out; 1129 } 1130 1131 memset(next, 0, sizeof(*next)); 1132 next->entry.d_name = next->name; 1133 memcpy(next->name, 1134 &filename[pathlen], 1135 filelen - pathlen); 1136 1137 SIMPLEQ_INSERT_TAIL(&dir->next, next, 1138 link); 1139 current = next; 1140 } 1141 } 1142 1143 if (fat_entries[i].flags & FILE_IS_LAST_ENTRY) { 1144 last_entry_found = true; 1145 break; 1146 } 1147 1148 /* Move to next fat_entry. */ 1149 fat_address += sizeof(struct rpmb_fat_entry); 1150 } 1151 } 1152 1153 /* No directories were found. */ 1154 if (!current) { 1155 res = TEE_ERROR_NO_DATA; 1156 goto out; 1157 } 1158 1159 res = TEE_SUCCESS; 1160 1161 out: 1162 if (res != TEE_SUCCESS) 1163 tee_rpmb_fs_dir_free(dir); 1164 if (fat_entries) 1165 free(fat_entries); 1166 1167 return res; 1168 } 1169 1170 static TEE_Result tee_rpmb_fs_opendir_internal(const char *path, 1171 tee_fs_dir **dir) 1172 { 1173 uint32_t len; 1174 uint32_t max_size; 1175 char path_local[TEE_RPMB_FS_FILENAME_LENGTH]; 1176 TEE_Result res = TEE_ERROR_GENERIC; 1177 tee_fs_dir *rpmb_dir = NULL; 1178 1179 if (!path || !dir) { 1180 res = TEE_ERROR_BAD_PARAMETERS; 1181 goto out; 1182 } 1183 1184 /* 1185 * There must be room for at least the NULL char and a char for the 1186 * filename after the path. 1187 */ 1188 max_size = TEE_RPMB_FS_FILENAME_LENGTH - 2; 1189 len = strlen(path); 1190 if (len > max_size || len == 0) { 1191 res = TEE_ERROR_BAD_PARAMETERS; 1192 goto out; 1193 } 1194 1195 memset(path_local, 0, sizeof(path_local)); 1196 memcpy(path_local, path, len); 1197 1198 /* Add a slash to correctly match the full directory name. */ 1199 if (path_local[len - 1] != '/') 1200 path_local[len] = '/'; 1201 1202 rpmb_dir = calloc(1, sizeof(tee_fs_dir)); 1203 if (!rpmb_dir) { 1204 res = TEE_ERROR_OUT_OF_MEMORY; 1205 goto out; 1206 } 1207 SIMPLEQ_INIT(&rpmb_dir->next); 1208 1209 res = tee_rpmb_fs_dir_populate(path_local, rpmb_dir); 1210 if (res != TEE_SUCCESS) { 1211 free(rpmb_dir); 1212 rpmb_dir = NULL; 1213 goto out; 1214 } 1215 1216 *dir = rpmb_dir; 1217 1218 out: 1219 return res; 1220 } 1221 1222 tee_fs_dir *tee_rpmb_fs_opendir(const char *path) 1223 { 1224 tee_fs_dir *dir = NULL; 1225 TEE_Result res = TEE_ERROR_GENERIC; 1226 1227 res = tee_rpmb_fs_opendir_internal(path, &dir); 1228 if (res != TEE_SUCCESS) 1229 dir = NULL; 1230 1231 return dir; 1232 } 1233 1234 1235 struct tee_fs_dirent *tee_rpmb_fs_readdir(tee_fs_dir *dir) 1236 { 1237 if (!dir) 1238 return NULL; 1239 1240 free(dir->current); 1241 1242 dir->current = SIMPLEQ_FIRST(&dir->next); 1243 if (!dir->current) 1244 return NULL; 1245 1246 SIMPLEQ_REMOVE_HEAD(&dir->next, link); 1247 1248 return &dir->current->entry; 1249 } 1250 1251 int tee_rpmb_fs_closedir(tee_fs_dir *dir) 1252 { 1253 TEE_Result res = TEE_ERROR_GENERIC; 1254 1255 if (!dir) { 1256 res = TEE_SUCCESS; 1257 goto out; 1258 } 1259 1260 tee_rpmb_fs_dir_free(dir); 1261 free(dir); 1262 res = TEE_SUCCESS; 1263 out: 1264 if (res == TEE_SUCCESS) 1265 return 0; 1266 1267 return -1; 1268 } 1269 1270 int tee_rpmb_fs_rmdir(const char *path) 1271 { 1272 tee_fs_dir *dir = NULL; 1273 TEE_Result res = TEE_ERROR_GENERIC; 1274 int ret = -1; 1275 1276 /* Open the directory anyting other than NO_DATA is a failure */ 1277 res = tee_rpmb_fs_opendir_internal(path, &dir); 1278 if (res == TEE_SUCCESS) { 1279 tee_rpmb_fs_closedir(dir); 1280 ret = -1; 1281 1282 } else if (res == TEE_ERROR_NO_DATA) { 1283 ret = 0; 1284 1285 } else { 1286 /* The case any other failure is returned */ 1287 ret = -1; 1288 } 1289 1290 1291 return ret; 1292 } 1293 1294 TEE_Result tee_rpmb_fs_stat(const char *filename, 1295 struct tee_rpmb_fs_stat *stat) 1296 { 1297 TEE_Result res = TEE_ERROR_GENERIC; 1298 struct rpmb_file_handle *fh = NULL; 1299 1300 if (!stat || !filename) { 1301 res = TEE_ERROR_BAD_PARAMETERS; 1302 goto out; 1303 } 1304 1305 fh = alloc_file_handle(filename); 1306 if (!fh) { 1307 res = TEE_ERROR_OUT_OF_MEMORY; 1308 goto out; 1309 } 1310 1311 res = read_fat(fh, NULL); 1312 if (res != TEE_SUCCESS) 1313 goto out; 1314 1315 stat->size = (size_t)fh->fat_entry.data_size; 1316 stat->reserved = 0; 1317 1318 out: 1319 free(fh); 1320 return res; 1321 } 1322 1323 int tee_rpmb_fs_access(const char *filename, int mode) 1324 { 1325 struct tee_rpmb_fs_stat stat; 1326 TEE_Result res; 1327 1328 /* Mode is currently ignored, this only checks for existence */ 1329 (void)mode; 1330 1331 res = tee_rpmb_fs_stat(filename, &stat); 1332 1333 if (res == TEE_SUCCESS) 1334 return 0; 1335 1336 return -1; 1337 } 1338 1339 static struct tee_fs_fd *tee_fs_fd_lookup(int fd) 1340 { 1341 return handle_lookup(&fs_handle_db, fd); 1342 } 1343 1344 static int tee_fs_close(int fd) 1345 { 1346 struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); 1347 1348 return tee_fs_common_close(fdp); 1349 } 1350 1351 static int tee_fs_read(TEE_Result *errno, int fd, void *buf, size_t len) 1352 { 1353 struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); 1354 1355 return tee_fs_common_read(errno, fdp, buf, len); 1356 } 1357 1358 static int tee_fs_write(TEE_Result *errno, int fd, const void *buf, size_t len) 1359 { 1360 struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); 1361 1362 return tee_fs_common_write(errno, fdp, buf, len); 1363 } 1364 1365 static tee_fs_off_t tee_fs_lseek(TEE_Result *errno, 1366 int fd, tee_fs_off_t offset, int whence) 1367 { 1368 struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); 1369 1370 return tee_fs_common_lseek(errno, fdp, offset, whence); 1371 } 1372 1373 static int tee_fs_ftruncate(TEE_Result *errno, int fd, tee_fs_off_t length) 1374 { 1375 struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); 1376 1377 return tee_fs_common_ftruncate(errno, fdp, length); 1378 } 1379 1380 struct tee_file_operations tee_file_ops = { 1381 .open = tee_fs_common_open, 1382 .close = tee_fs_close, 1383 .read = tee_fs_read, 1384 .write = tee_fs_write, 1385 .lseek = tee_fs_lseek, 1386 .ftruncate = tee_fs_ftruncate, 1387 .rename = tee_fs_common_rename, 1388 .unlink = tee_fs_common_unlink, 1389 .mkdir = tee_fs_common_mkdir, 1390 .opendir = tee_fs_common_opendir, 1391 .closedir = tee_fs_common_closedir, 1392 .readdir = tee_fs_common_readdir, 1393 .rmdir = tee_fs_common_rmdir, 1394 .access = tee_fs_common_access 1395 }; 1396