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