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