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