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 newsize; 674 uint8_t *newbuf = NULL; 675 uintptr_t newaddr; 676 677 if (!size) 678 return 0; 679 680 if (!buf) { 681 res = TEE_ERROR_BAD_PARAMETERS; 682 goto out; 683 } 684 685 if (!fs_par) { 686 res = TEE_ERROR_GENERIC; 687 goto out; 688 } 689 690 fh = handle_lookup(&fs_handle_db, fd); 691 if (!fh) { 692 res = TEE_ERROR_BAD_PARAMETERS; 693 goto out; 694 } 695 dump_fh(fh); 696 697 /* Upper memory allocation must be used for RPMB_FS. */ 698 pool_result = tee_mm_init(&p, 699 RPMB_STORAGE_START_ADDRESS, 700 fs_par->max_rpmb_address, 701 RPMB_BLOCK_SIZE_SHIFT, 702 TEE_MM_POOL_HI_ALLOC); 703 if (!pool_result) { 704 res = TEE_ERROR_OUT_OF_MEMORY; 705 goto out; 706 } 707 708 res = read_fat(fh, &p); 709 if (res != TEE_SUCCESS) 710 goto out; 711 712 TEE_ASSERT(!(fh->fat_entry.flags & FILE_IS_LAST_ENTRY)); 713 714 newsize = fh->pos + size; 715 if (newsize <= fh->fat_entry.data_size) { 716 /* Modifying file content */ 717 718 res = tee_rpmb_write(DEV_ID, 719 fh->fat_entry.start_address + fh->pos, 720 buf, size); 721 if (res != TEE_SUCCESS) 722 goto out; 723 } else { 724 /* Extend file: allocate, read, update, write */ 725 726 mm = tee_mm_alloc(&p, newsize); 727 newbuf = calloc(newsize, 1); 728 if (!mm || !newbuf) { 729 res = TEE_ERROR_OUT_OF_MEMORY; 730 goto out; 731 } 732 733 if (fh->fat_entry.data_size) { 734 res = tee_rpmb_read(DEV_ID, 735 fh->fat_entry.start_address, 736 newbuf, fh->fat_entry.data_size); 737 if (res != TEE_SUCCESS) 738 goto out; 739 } 740 741 memcpy(newbuf + fh->pos, buf, size); 742 743 newaddr = tee_mm_get_smem(mm); 744 res = tee_rpmb_write(DEV_ID, newaddr, newbuf, newsize); 745 if (res != TEE_SUCCESS) 746 goto out; 747 748 fh->fat_entry.data_size = newsize; 749 fh->fat_entry.start_address = newaddr; 750 res = write_fat_entry(fh, true); 751 if (res != TEE_SUCCESS) 752 goto out; 753 } 754 755 fh->pos = newsize; 756 out: 757 if (pool_result) 758 tee_mm_final(&p); 759 if (newbuf) 760 free(newbuf); 761 762 if (res == TEE_SUCCESS) 763 return size; 764 765 return -1; 766 } 767 768 tee_fs_off_t tee_rpmb_fs_lseek(int fd, tee_fs_off_t offset, int whence) 769 { 770 struct rpmb_file_handle *fh; 771 TEE_Result res; 772 tee_fs_off_t ret = -1; 773 tee_fs_off_t new_pos; 774 775 fh = handle_lookup(&fs_handle_db, fd); 776 if (!fh) 777 return TEE_ERROR_BAD_PARAMETERS; 778 779 res = read_fat(fh, NULL); 780 if (res != TEE_SUCCESS) 781 return -1; 782 783 switch (whence) { 784 case TEE_FS_SEEK_SET: 785 new_pos = offset; 786 break; 787 788 case TEE_FS_SEEK_CUR: 789 new_pos = fh->pos + offset; 790 break; 791 792 case TEE_FS_SEEK_END: 793 new_pos = fh->fat_entry.data_size + offset; 794 break; 795 796 default: 797 goto exit; 798 } 799 800 if (new_pos < 0) 801 new_pos = 0; 802 803 if (new_pos > TEE_DATA_MAX_POSITION) { 804 EMSG("Position is beyond TEE_DATA_MAX_POSITION"); 805 goto exit; 806 } 807 808 ret = fh->pos = new_pos; 809 exit: 810 return ret; 811 } 812 813 TEE_Result tee_rpmb_fs_rm(const char *filename) 814 { 815 TEE_Result res = TEE_ERROR_GENERIC; 816 struct rpmb_file_handle *fh = NULL; 817 818 if (!filename || strlen(filename) >= TEE_RPMB_FS_FILENAME_LENGTH - 1) { 819 res = TEE_ERROR_BAD_PARAMETERS; 820 goto out; 821 } 822 823 fh = alloc_file_handle(filename); 824 if (!fh) { 825 res = TEE_ERROR_OUT_OF_MEMORY; 826 goto out; 827 } 828 829 res = read_fat(fh, NULL); 830 if (res != TEE_SUCCESS) 831 goto out; 832 833 /* Clear this file entry. */ 834 memset(&fh->fat_entry, 0, sizeof(struct rpmb_fat_entry)); 835 res = write_fat_entry(fh, false); 836 837 out: 838 free(fh); 839 IMSG("Deleting file %s returned 0x%x\n", filename, res); 840 return res; 841 } 842 843 TEE_Result tee_rpmb_fs_rename(const char *old_name, const char *new_name) 844 { 845 TEE_Result res = TEE_ERROR_GENERIC; 846 struct rpmb_file_handle *fh_old = NULL; 847 struct rpmb_file_handle *fh_new = NULL; 848 uint32_t old_len; 849 uint32_t new_len; 850 851 if (!old_name || !new_name) { 852 res = TEE_ERROR_BAD_PARAMETERS; 853 goto out; 854 } 855 856 old_len = strlen(old_name); 857 new_len = strlen(new_name); 858 859 if ((old_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || 860 (new_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || (new_len == 0)) { 861 862 res = TEE_ERROR_BAD_PARAMETERS; 863 goto out; 864 } 865 866 fh_old = alloc_file_handle(old_name); 867 if (!fh_old) { 868 res = TEE_ERROR_OUT_OF_MEMORY; 869 goto out; 870 } 871 872 fh_new = alloc_file_handle(new_name); 873 if (!fh_new) { 874 res = TEE_ERROR_OUT_OF_MEMORY; 875 goto out; 876 } 877 878 res = read_fat(fh_old, NULL); 879 if (res != TEE_SUCCESS) 880 goto out; 881 882 res = read_fat(fh_new, NULL); 883 if (res == TEE_SUCCESS) { 884 res = TEE_ERROR_BAD_PARAMETERS; 885 goto out; 886 } 887 888 memset(fh_old->fat_entry.filename, 0, TEE_RPMB_FS_FILENAME_LENGTH); 889 memcpy(fh_old->fat_entry.filename, new_name, new_len); 890 891 res = write_fat_entry(fh_old, false); 892 893 out: 894 free(fh_old); 895 free(fh_new); 896 897 return res; 898 } 899 900 int tee_rpmb_fs_mkdir(const char *path __unused, tee_fs_mode_t mode __unused) 901 { 902 /* 903 * FIXME: mkdir() should really create some entry in the FAT so that 904 * access() would return success when the directory exists but is 905 * empty. This does not matter for the current use cases. 906 */ 907 return 0; 908 } 909 910 int tee_rpmb_fs_ftruncate(int fd, tee_fs_off_t length) 911 { 912 struct rpmb_file_handle *fh; 913 tee_mm_pool_t p; 914 bool pool_result = false; 915 tee_mm_entry_t *mm; 916 uint32_t newsize; 917 uint8_t *newbuf = NULL; 918 uintptr_t newaddr; 919 TEE_Result res = TEE_ERROR_GENERIC; 920 921 if (length < 0 || length > INT32_MAX) { 922 res = TEE_ERROR_BAD_PARAMETERS; 923 goto out; 924 } 925 newsize = length; 926 927 fh = handle_lookup(&fs_handle_db, fd); 928 if (!fh) { 929 res = TEE_ERROR_BAD_PARAMETERS; 930 goto out; 931 } 932 933 res = read_fat(fh, NULL); 934 if (res != TEE_SUCCESS) 935 goto out; 936 937 if (newsize > fh->fat_entry.data_size) { 938 /* Extend file */ 939 940 pool_result = tee_mm_init(&p, 941 RPMB_STORAGE_START_ADDRESS, 942 fs_par->max_rpmb_address, 943 RPMB_BLOCK_SIZE_SHIFT, 944 TEE_MM_POOL_HI_ALLOC); 945 if (!pool_result) { 946 res = TEE_ERROR_OUT_OF_MEMORY; 947 goto out; 948 } 949 res = read_fat(fh, &p); 950 if (res != TEE_SUCCESS) 951 goto out; 952 953 mm = tee_mm_alloc(&p, newsize); 954 newbuf = calloc(newsize, 1); 955 if (!mm || !newbuf) { 956 res = TEE_ERROR_OUT_OF_MEMORY; 957 goto out; 958 } 959 960 if (fh->fat_entry.data_size) { 961 res = tee_rpmb_read(DEV_ID, 962 fh->fat_entry.start_address, 963 newbuf, fh->fat_entry.data_size); 964 if (res != TEE_SUCCESS) 965 goto out; 966 } 967 968 newaddr = tee_mm_get_smem(mm); 969 res = tee_rpmb_write(DEV_ID, newaddr, newbuf, newsize); 970 if (res != TEE_SUCCESS) 971 goto out; 972 973 } else { 974 /* Don't change file location */ 975 newaddr = fh->fat_entry.start_address; 976 } 977 978 /* fh->pos is unchanged */ 979 fh->fat_entry.data_size = newsize; 980 fh->fat_entry.start_address = newaddr; 981 res = write_fat_entry(fh, true); 982 983 out: 984 if (pool_result) 985 tee_mm_final(&p); 986 if (newbuf) 987 free(newbuf); 988 989 if (res == TEE_SUCCESS) 990 return 0; 991 992 return -1; 993 } 994 995 static void tee_rpmb_fs_dir_free(tee_fs_dir *dir) 996 { 997 struct tee_rpmb_fs_dirent *e; 998 999 if (!dir) 1000 return; 1001 1002 free(dir->current); 1003 1004 while ((e = SIMPLEQ_FIRST(&dir->next))) { 1005 SIMPLEQ_REMOVE_HEAD(&dir->next, link); 1006 free(e); 1007 } 1008 } 1009 1010 static TEE_Result tee_rpmb_fs_dir_populate(const char *path, tee_fs_dir *dir) 1011 { 1012 struct tee_rpmb_fs_dirent *current = NULL; 1013 struct rpmb_fat_entry *fat_entries = NULL; 1014 uint32_t fat_address; 1015 uint32_t filelen; 1016 char *filename; 1017 int i; 1018 bool last_entry_found = false; 1019 bool matched; 1020 struct tee_rpmb_fs_dirent *next = NULL; 1021 uint32_t pathlen; 1022 TEE_Result res = TEE_ERROR_GENERIC; 1023 uint32_t size; 1024 char temp; 1025 1026 res = rpmb_fs_setup(); 1027 if (res != TEE_SUCCESS) 1028 goto out; 1029 1030 res = get_fat_start_address(&fat_address); 1031 if (res != TEE_SUCCESS) 1032 goto out; 1033 1034 size = N_ENTRIES * sizeof(struct rpmb_fat_entry); 1035 fat_entries = malloc(size); 1036 if (!fat_entries) { 1037 res = TEE_ERROR_OUT_OF_MEMORY; 1038 goto out; 1039 } 1040 1041 pathlen = strlen(path); 1042 while (!last_entry_found) { 1043 res = tee_rpmb_read(DEV_ID, fat_address, 1044 (uint8_t *)fat_entries, size); 1045 if (res != TEE_SUCCESS) 1046 goto out; 1047 1048 for (i = 0; i < N_ENTRIES; i++) { 1049 filename = fat_entries[i].filename; 1050 if (fat_entries[i].flags & FILE_IS_ACTIVE) { 1051 matched = false; 1052 filelen = strlen(filename); 1053 if (filelen > pathlen) { 1054 temp = filename[pathlen]; 1055 filename[pathlen] = '\0'; 1056 if (strcmp(filename, path) == 0) 1057 matched = true; 1058 1059 filename[pathlen] = temp; 1060 } 1061 1062 if (matched) { 1063 next = malloc(sizeof(*next)); 1064 if (!next) { 1065 res = TEE_ERROR_OUT_OF_MEMORY; 1066 goto out; 1067 } 1068 1069 memset(next, 0, sizeof(*next)); 1070 next->entry.d_name = next->name; 1071 memcpy(next->name, 1072 &filename[pathlen], 1073 filelen - pathlen); 1074 1075 SIMPLEQ_INSERT_TAIL(&dir->next, next, 1076 link); 1077 current = next; 1078 } 1079 } 1080 1081 if (fat_entries[i].flags & FILE_IS_LAST_ENTRY) { 1082 last_entry_found = true; 1083 break; 1084 } 1085 1086 /* Move to next fat_entry. */ 1087 fat_address += sizeof(struct rpmb_fat_entry); 1088 } 1089 } 1090 1091 /* No directories were found. */ 1092 if (!current) { 1093 res = TEE_ERROR_NO_DATA; 1094 goto out; 1095 } 1096 1097 res = TEE_SUCCESS; 1098 1099 out: 1100 if (res != TEE_SUCCESS) 1101 tee_rpmb_fs_dir_free(dir); 1102 if (fat_entries) 1103 free(fat_entries); 1104 1105 return res; 1106 } 1107 1108 static TEE_Result tee_rpmb_fs_opendir_internal(const char *path, 1109 tee_fs_dir **dir) 1110 { 1111 uint32_t len; 1112 uint32_t max_size; 1113 char path_local[TEE_RPMB_FS_FILENAME_LENGTH]; 1114 TEE_Result res = TEE_ERROR_GENERIC; 1115 tee_fs_dir *rpmb_dir = NULL; 1116 1117 if (!path || !dir) { 1118 res = TEE_ERROR_BAD_PARAMETERS; 1119 goto out; 1120 } 1121 1122 /* 1123 * There must be room for at least the NULL char and a char for the 1124 * filename after the path. 1125 */ 1126 max_size = TEE_RPMB_FS_FILENAME_LENGTH - 2; 1127 len = strlen(path); 1128 if (len > max_size || len == 0) { 1129 res = TEE_ERROR_BAD_PARAMETERS; 1130 goto out; 1131 } 1132 1133 memset(path_local, 0, sizeof(path_local)); 1134 memcpy(path_local, path, len); 1135 1136 /* Add a slash to correctly match the full directory name. */ 1137 if (path_local[len - 1] != '/') 1138 path_local[len] = '/'; 1139 1140 rpmb_dir = calloc(1, sizeof(tee_fs_dir)); 1141 if (!rpmb_dir) { 1142 res = TEE_ERROR_OUT_OF_MEMORY; 1143 goto out; 1144 } 1145 SIMPLEQ_INIT(&rpmb_dir->next); 1146 1147 res = tee_rpmb_fs_dir_populate(path_local, rpmb_dir); 1148 if (res != TEE_SUCCESS) { 1149 free(rpmb_dir); 1150 rpmb_dir = NULL; 1151 goto out; 1152 } 1153 1154 *dir = rpmb_dir; 1155 1156 out: 1157 return res; 1158 } 1159 1160 tee_fs_dir *tee_rpmb_fs_opendir(const char *path) 1161 { 1162 tee_fs_dir *dir = NULL; 1163 TEE_Result res = TEE_ERROR_GENERIC; 1164 1165 res = tee_rpmb_fs_opendir_internal(path, &dir); 1166 if (res != TEE_SUCCESS) 1167 dir = NULL; 1168 1169 return dir; 1170 } 1171 1172 1173 struct tee_fs_dirent *tee_rpmb_fs_readdir(tee_fs_dir *dir) 1174 { 1175 if (!dir) 1176 return NULL; 1177 1178 free(dir->current); 1179 1180 dir->current = SIMPLEQ_FIRST(&dir->next); 1181 if (!dir->current) 1182 return NULL; 1183 1184 SIMPLEQ_REMOVE_HEAD(&dir->next, link); 1185 1186 return &dir->current->entry; 1187 } 1188 1189 int tee_rpmb_fs_closedir(tee_fs_dir *dir) 1190 { 1191 TEE_Result res = TEE_ERROR_GENERIC; 1192 1193 if (!dir) { 1194 res = TEE_SUCCESS; 1195 goto out; 1196 } 1197 1198 tee_rpmb_fs_dir_free(dir); 1199 free(dir); 1200 res = TEE_SUCCESS; 1201 out: 1202 if (res == TEE_SUCCESS) 1203 return 0; 1204 1205 return -1; 1206 } 1207 1208 int tee_rpmb_fs_rmdir(const char *path) 1209 { 1210 tee_fs_dir *dir = NULL; 1211 TEE_Result res = TEE_ERROR_GENERIC; 1212 int ret = -1; 1213 1214 /* Open the directory anyting other than NO_DATA is a failure */ 1215 res = tee_rpmb_fs_opendir_internal(path, &dir); 1216 if (res == TEE_SUCCESS) { 1217 tee_rpmb_fs_closedir(dir); 1218 ret = -1; 1219 1220 } else if (res == TEE_ERROR_NO_DATA) { 1221 ret = 0; 1222 1223 } else { 1224 /* The case any other failure is returned */ 1225 ret = -1; 1226 } 1227 1228 1229 return ret; 1230 } 1231 1232 TEE_Result tee_rpmb_fs_stat(const char *filename, 1233 struct tee_rpmb_fs_stat *stat) 1234 { 1235 TEE_Result res = TEE_ERROR_GENERIC; 1236 struct rpmb_file_handle *fh = NULL; 1237 1238 if (!stat || !filename) { 1239 res = TEE_ERROR_BAD_PARAMETERS; 1240 goto out; 1241 } 1242 1243 fh = alloc_file_handle(filename); 1244 if (!fh) { 1245 res = TEE_ERROR_OUT_OF_MEMORY; 1246 goto out; 1247 } 1248 1249 res = read_fat(fh, NULL); 1250 if (res != TEE_SUCCESS) 1251 goto out; 1252 1253 stat->size = (size_t)fh->fat_entry.data_size; 1254 stat->reserved = 0; 1255 1256 out: 1257 free(fh); 1258 return res; 1259 } 1260 1261 int tee_rpmb_fs_access(const char *filename, int mode) 1262 { 1263 struct tee_rpmb_fs_stat stat; 1264 TEE_Result res; 1265 1266 /* Mode is currently ignored, this only checks for existence */ 1267 (void)mode; 1268 1269 res = tee_rpmb_fs_stat(filename, &stat); 1270 1271 if (res == TEE_SUCCESS) 1272 return 0; 1273 1274 return -1; 1275 } 1276 1277