1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2015, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <config.h> 8 #include <kernel/mutex.h> 9 #include <kernel/nv_counter.h> 10 #include <kernel/panic.h> 11 #include <kernel/thread.h> 12 #include <kernel/user_access.h> 13 #include <mempool.h> 14 #include <mm/core_memprot.h> 15 #include <mm/tee_pager.h> 16 #include <optee_rpc_cmd.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sys/queue.h> 20 #include <tee/fs_dirfile.h> 21 #include <tee/fs_htree.h> 22 #include <tee/tee_fs.h> 23 #include <tee/tee_fs_rpc.h> 24 #include <tee/tee_pobj.h> 25 #include <trace.h> 26 #include <utee_defines.h> 27 #include <util.h> 28 29 #define BLOCK_SHIFT 12 30 31 #define BLOCK_SIZE (1 << BLOCK_SHIFT) 32 33 struct tee_fs_fd { 34 struct tee_fs_htree *ht; 35 int fd; 36 struct tee_fs_dirfile_fileh dfh; 37 const TEE_UUID *uuid; 38 }; 39 40 struct tee_fs_dir { 41 struct tee_fs_dirfile_dirh *dirh; 42 int idx; 43 struct tee_fs_dirent d; 44 const TEE_UUID *uuid; 45 }; 46 47 static int pos_to_block_num(int position) 48 { 49 return position >> BLOCK_SHIFT; 50 } 51 52 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; 53 54 static void *get_tmp_block(void) 55 { 56 return mempool_alloc(mempool_default, BLOCK_SIZE); 57 } 58 59 static void put_tmp_block(void *tmp_block) 60 { 61 mempool_free(mempool_default, tmp_block); 62 } 63 64 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos, 65 const void *buf_core, 66 const void *buf_user, size_t len) 67 { 68 TEE_Result res; 69 size_t start_block_num = pos_to_block_num(pos); 70 size_t end_block_num = pos_to_block_num(pos + len - 1); 71 size_t remain_bytes = len; 72 uint8_t *data_core_ptr = (uint8_t *)buf_core; 73 uint8_t *data_user_ptr = (uint8_t *)buf_user; 74 uint8_t *block; 75 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 76 77 /* 78 * It doesn't make sense to call this function if nothing is to be 79 * written. This also guards against end_block_num getting an 80 * unexpected value when pos == 0 and len == 0. 81 */ 82 if (!len) 83 return TEE_ERROR_BAD_PARAMETERS; 84 85 block = get_tmp_block(); 86 if (!block) 87 return TEE_ERROR_OUT_OF_MEMORY; 88 89 while (start_block_num <= end_block_num) { 90 size_t offset = pos % BLOCK_SIZE; 91 size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE); 92 93 if (size_to_write + offset > BLOCK_SIZE) 94 size_to_write = BLOCK_SIZE - offset; 95 96 if (start_block_num * BLOCK_SIZE < 97 ROUNDUP(meta->length, BLOCK_SIZE)) { 98 res = tee_fs_htree_read_block(&fdp->ht, 99 start_block_num, block); 100 if (res != TEE_SUCCESS) 101 goto exit; 102 } else { 103 memset(block, 0, BLOCK_SIZE); 104 } 105 106 if (data_core_ptr) { 107 memcpy(block + offset, data_core_ptr, size_to_write); 108 } else if (data_user_ptr) { 109 res = copy_from_user(block + offset, data_user_ptr, 110 size_to_write); 111 if (res) 112 return res; 113 } else { 114 memset(block + offset, 0, size_to_write); 115 } 116 117 res = tee_fs_htree_write_block(&fdp->ht, start_block_num, 118 block); 119 if (res != TEE_SUCCESS) 120 goto exit; 121 122 if (data_core_ptr) 123 data_core_ptr += size_to_write; 124 if (data_user_ptr) 125 data_user_ptr += size_to_write; 126 remain_bytes -= size_to_write; 127 start_block_num++; 128 pos += size_to_write; 129 } 130 131 if (pos > meta->length) { 132 meta->length = pos; 133 tee_fs_htree_meta_set_dirty(fdp->ht); 134 } 135 136 exit: 137 if (block) 138 put_tmp_block(block); 139 return res; 140 } 141 142 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx, 143 uint8_t vers, size_t *offs, size_t *size) 144 { 145 const size_t node_size = sizeof(struct tee_fs_htree_node_image); 146 const size_t block_nodes = BLOCK_SIZE / (node_size * 2); 147 size_t pbn; 148 size_t bidx; 149 150 assert(vers == 0 || vers == 1); 151 152 /* 153 * File layout 154 * [demo with input: 155 * BLOCK_SIZE = 4096, 156 * node_size = 66, 157 * block_nodes = 4096/(66*2) = 31 ] 158 * 159 * phys block 0: 160 * tee_fs_htree_image vers 0 @ offs = 0 161 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image) 162 * 163 * phys block 1: 164 * tee_fs_htree_node_image 0 vers 0 @ offs = 0 165 * tee_fs_htree_node_image 0 vers 1 @ offs = node_size 166 * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2 167 * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3 168 * ... 169 * tee_fs_htree_node_image 30 vers 0 @ offs = node_size * 60 170 * tee_fs_htree_node_image 30 vers 1 @ offs = node_size * 61 171 * 172 * phys block 2: 173 * data block 0 vers 0 174 * 175 * phys block 3: 176 * data block 0 vers 1 177 * 178 * ... 179 * phys block 62: 180 * data block 30 vers 0 181 * 182 * phys block 63: 183 * data block 30 vers 1 184 * 185 * phys block 64: 186 * tee_fs_htree_node_image 31 vers 0 @ offs = 0 187 * tee_fs_htree_node_image 31 vers 1 @ offs = node_size 188 * tee_fs_htree_node_image 32 vers 0 @ offs = node_size * 2 189 * tee_fs_htree_node_image 32 vers 1 @ offs = node_size * 3 190 * ... 191 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 60 192 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 61 193 * 194 * phys block 65: 195 * data block 31 vers 0 196 * 197 * phys block 66: 198 * data block 31 vers 1 199 * ... 200 */ 201 202 switch (type) { 203 case TEE_FS_HTREE_TYPE_HEAD: 204 *offs = sizeof(struct tee_fs_htree_image) * vers; 205 *size = sizeof(struct tee_fs_htree_image); 206 return TEE_SUCCESS; 207 case TEE_FS_HTREE_TYPE_NODE: 208 pbn = 1 + ((idx / block_nodes) * block_nodes * 2); 209 *offs = pbn * BLOCK_SIZE + 210 2 * node_size * (idx % block_nodes) + 211 node_size * vers; 212 *size = node_size; 213 return TEE_SUCCESS; 214 case TEE_FS_HTREE_TYPE_BLOCK: 215 bidx = 2 * idx + vers; 216 pbn = 2 + bidx + bidx / (block_nodes * 2 - 1); 217 *offs = pbn * BLOCK_SIZE; 218 *size = BLOCK_SIZE; 219 return TEE_SUCCESS; 220 default: 221 return TEE_ERROR_GENERIC; 222 } 223 } 224 225 static TEE_Result ree_fs_rpc_read_init(void *aux, 226 struct tee_fs_rpc_operation *op, 227 enum tee_fs_htree_type type, size_t idx, 228 uint8_t vers, void **data) 229 { 230 struct tee_fs_fd *fdp = aux; 231 TEE_Result res; 232 size_t offs; 233 size_t size; 234 235 res = get_offs_size(type, idx, vers, &offs, &size); 236 if (res != TEE_SUCCESS) 237 return res; 238 239 return tee_fs_rpc_read_init(op, OPTEE_RPC_CMD_FS, fdp->fd, 240 offs, size, data); 241 } 242 243 static TEE_Result ree_fs_rpc_write_init(void *aux, 244 struct tee_fs_rpc_operation *op, 245 enum tee_fs_htree_type type, size_t idx, 246 uint8_t vers, void **data) 247 { 248 struct tee_fs_fd *fdp = aux; 249 TEE_Result res; 250 size_t offs; 251 size_t size; 252 253 res = get_offs_size(type, idx, vers, &offs, &size); 254 if (res != TEE_SUCCESS) 255 return res; 256 257 return tee_fs_rpc_write_init(op, OPTEE_RPC_CMD_FS, fdp->fd, 258 offs, size, data); 259 } 260 261 static const struct tee_fs_htree_storage ree_fs_storage_ops = { 262 .block_size = BLOCK_SIZE, 263 .rpc_read_init = ree_fs_rpc_read_init, 264 .rpc_read_final = tee_fs_rpc_read_final, 265 .rpc_write_init = ree_fs_rpc_write_init, 266 .rpc_write_final = tee_fs_rpc_write_final, 267 }; 268 269 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, 270 tee_fs_off_t new_file_len) 271 { 272 TEE_Result res; 273 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 274 275 if ((size_t)new_file_len > meta->length) { 276 size_t ext_len = new_file_len - meta->length; 277 278 res = out_of_place_write(fdp, meta->length, NULL, NULL, 279 ext_len); 280 if (res != TEE_SUCCESS) 281 return res; 282 } else { 283 size_t offs; 284 size_t sz; 285 286 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, 287 ROUNDUP(new_file_len, BLOCK_SIZE) / 288 BLOCK_SIZE, 1, &offs, &sz); 289 if (res != TEE_SUCCESS) 290 return res; 291 292 res = tee_fs_htree_truncate(&fdp->ht, 293 new_file_len / BLOCK_SIZE); 294 if (res != TEE_SUCCESS) 295 return res; 296 297 res = tee_fs_rpc_truncate(OPTEE_RPC_CMD_FS, fdp->fd, 298 offs + sz); 299 if (res != TEE_SUCCESS) 300 return res; 301 302 meta->length = new_file_len; 303 tee_fs_htree_meta_set_dirty(fdp->ht); 304 } 305 306 return TEE_SUCCESS; 307 } 308 309 static TEE_Result ree_fs_read_primitive(struct tee_file_handle *fh, size_t pos, 310 void *buf_core, void *buf_user, 311 size_t *len) 312 { 313 TEE_Result res; 314 int start_block_num; 315 int end_block_num; 316 size_t remain_bytes; 317 uint8_t *data_core_ptr = buf_core; 318 uint8_t *data_user_ptr = buf_user; 319 uint8_t *block = NULL; 320 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 321 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 322 323 /* One of buf_core and buf_user must be NULL */ 324 assert(!buf_core || !buf_user); 325 326 remain_bytes = *len; 327 if ((pos + remain_bytes) < remain_bytes || pos > meta->length) 328 remain_bytes = 0; 329 else if (pos + remain_bytes > meta->length) 330 remain_bytes = meta->length - pos; 331 332 *len = remain_bytes; 333 334 if (!remain_bytes) { 335 res = TEE_SUCCESS; 336 goto exit; 337 } 338 339 start_block_num = pos_to_block_num(pos); 340 end_block_num = pos_to_block_num(pos + remain_bytes - 1); 341 342 block = get_tmp_block(); 343 if (!block) { 344 res = TEE_ERROR_OUT_OF_MEMORY; 345 goto exit; 346 } 347 348 while (start_block_num <= end_block_num) { 349 size_t offset = pos % BLOCK_SIZE; 350 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); 351 352 if (size_to_read + offset > BLOCK_SIZE) 353 size_to_read = BLOCK_SIZE - offset; 354 355 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block); 356 if (res != TEE_SUCCESS) 357 goto exit; 358 359 if (data_core_ptr) { 360 memcpy(data_core_ptr, block + offset, size_to_read); 361 data_core_ptr += size_to_read; 362 } else if (data_user_ptr) { 363 res = copy_to_user(data_user_ptr, block + offset, 364 size_to_read); 365 if (res) 366 goto exit; 367 data_user_ptr += size_to_read; 368 } 369 370 remain_bytes -= size_to_read; 371 pos += size_to_read; 372 373 start_block_num++; 374 } 375 res = TEE_SUCCESS; 376 exit: 377 if (block) 378 put_tmp_block(block); 379 return res; 380 } 381 382 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos, 383 void *buf_core, void *buf_user, size_t *len) 384 { 385 TEE_Result res; 386 387 mutex_lock(&ree_fs_mutex); 388 res = ree_fs_read_primitive(fh, pos, buf_core, buf_user, len); 389 mutex_unlock(&ree_fs_mutex); 390 391 return res; 392 } 393 394 static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos, 395 const void *buf_core, 396 const void *buf_user, size_t len) 397 { 398 TEE_Result res; 399 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 400 size_t file_size; 401 402 /* One of buf_core and buf_user must be NULL */ 403 assert(!buf_core || !buf_user); 404 405 if (!len) 406 return TEE_SUCCESS; 407 408 file_size = tee_fs_htree_get_meta(fdp->ht)->length; 409 410 if ((pos + len) < len) 411 return TEE_ERROR_BAD_PARAMETERS; 412 413 if (file_size < pos) { 414 res = ree_fs_ftruncate_internal(fdp, pos); 415 if (res != TEE_SUCCESS) 416 return res; 417 } 418 419 return out_of_place_write(fdp, pos, buf_core, buf_user, len); 420 } 421 422 static TEE_Result ree_fs_open_primitive(bool create, uint8_t *hash, 423 uint32_t min_counter, 424 const TEE_UUID *uuid, 425 struct tee_fs_dirfile_fileh *dfh, 426 struct tee_file_handle **fh) 427 { 428 TEE_Result res; 429 struct tee_fs_fd *fdp; 430 431 fdp = calloc(1, sizeof(struct tee_fs_fd)); 432 if (!fdp) 433 return TEE_ERROR_OUT_OF_MEMORY; 434 fdp->fd = -1; 435 fdp->uuid = uuid; 436 437 if (create) 438 res = tee_fs_rpc_create_dfh(OPTEE_RPC_CMD_FS, 439 dfh, &fdp->fd); 440 else 441 res = tee_fs_rpc_open_dfh(OPTEE_RPC_CMD_FS, dfh, &fdp->fd); 442 443 if (res != TEE_SUCCESS) 444 goto out; 445 446 res = tee_fs_htree_open(create, hash, min_counter, uuid, 447 &ree_fs_storage_ops, fdp, &fdp->ht); 448 out: 449 if (res == TEE_SUCCESS) { 450 if (dfh) 451 fdp->dfh = *dfh; 452 else 453 fdp->dfh.idx = -1; 454 *fh = (struct tee_file_handle *)fdp; 455 } else { 456 if (res == TEE_ERROR_SECURITY) 457 DMSG("Secure storage corruption detected"); 458 if (fdp->fd != -1) 459 tee_fs_rpc_close(OPTEE_RPC_CMD_FS, fdp->fd); 460 if (create) 461 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, dfh); 462 free(fdp); 463 } 464 465 return res; 466 } 467 468 static void ree_fs_close_primitive(struct tee_file_handle *fh) 469 { 470 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 471 472 if (fdp) { 473 tee_fs_htree_close(&fdp->ht); 474 tee_fs_rpc_close(OPTEE_RPC_CMD_FS, fdp->fd); 475 free(fdp); 476 } 477 } 478 479 static TEE_Result ree_dirf_commit_writes(struct tee_file_handle *fh, 480 uint8_t *hash, uint32_t *counter) 481 { 482 TEE_Result res; 483 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 484 485 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, counter); 486 487 if (!res && hash) 488 memcpy(hash, fdp->dfh.hash, sizeof(fdp->dfh.hash)); 489 490 return res; 491 } 492 493 static TEE_Result dirf_read(struct tee_file_handle *fh, size_t pos, void *buf, 494 size_t *len) 495 { 496 return ree_fs_read_primitive(fh, pos, buf, NULL, len); 497 } 498 499 static TEE_Result dirf_write(struct tee_file_handle *fh, size_t pos, 500 const void *buf, size_t len) 501 { 502 return ree_fs_write_primitive(fh, pos, buf, NULL, len); 503 } 504 505 static const struct tee_fs_dirfile_operations ree_dirf_ops = { 506 .open = ree_fs_open_primitive, 507 .close = ree_fs_close_primitive, 508 .read = dirf_read, 509 .write = dirf_write, 510 .commit_writes = ree_dirf_commit_writes, 511 }; 512 513 /* 514 * ree_fs_dirh is caching the dirfile handle to avoid frequent opening and 515 * closing of that handle. When ree_fs_dirh_refcount reaches 0, ree_fs_dirh 516 * will be freed. However, ree_fs_dirh_refcount > 0 is not a guarantee that 517 * ree_fs_dirh will not be freed, it may very well be freed earlier in an 518 * error path. get_dirh() must be used to get the ree_fs_dirh pointer each 519 * time it's needed if ree_fs_mutex has been unlocked in between. 520 */ 521 static struct tee_fs_dirfile_dirh *ree_fs_dirh; 522 static size_t ree_fs_dirh_refcount; 523 524 #ifdef CFG_REE_FS_INTEGRITY_RPMB 525 static struct tee_file_handle *ree_fs_rpmb_fh; 526 527 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh) 528 { 529 TEE_Result res; 530 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 531 uint8_t *hashp = NULL; 532 const char fname[] = "dirfile.db.hash"; 533 534 res = tee_rpmb_fs_raw_open(fname, false, &ree_fs_rpmb_fh); 535 if (!res) { 536 size_t l = sizeof(hash); 537 538 res = rpmb_fs_ops.read(ree_fs_rpmb_fh, 0, hash, NULL, &l); 539 if (res) 540 return res; 541 if (l == sizeof(hash)) 542 hashp = hash; 543 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 544 res = tee_rpmb_fs_raw_open(fname, true, &ree_fs_rpmb_fh); 545 } 546 if (res) 547 return res; 548 549 res = tee_fs_dirfile_open(false, hashp, 0, &ree_dirf_ops, dirh); 550 551 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 552 if (hashp) { 553 if (IS_ENABLED(CFG_REE_FS_ALLOW_RESET)) { 554 DMSG("dirf.db not found, clear hash in RPMB"); 555 res = rpmb_fs_ops.truncate(ree_fs_rpmb_fh, 0); 556 if (res) { 557 DMSG("Can't clear hash: %#"PRIx32, res); 558 res = TEE_ERROR_SECURITY; 559 goto out; 560 } 561 } else { 562 DMSG("dirf.db file not found"); 563 res = TEE_ERROR_SECURITY; 564 goto out; 565 } 566 } 567 568 res = tee_fs_dirfile_open(true, NULL, 0, &ree_dirf_ops, dirh); 569 } 570 571 out: 572 if (res) 573 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 574 575 return res; 576 } 577 578 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 579 { 580 TEE_Result res; 581 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 582 583 res = tee_fs_dirfile_commit_writes(dirh, hash, NULL); 584 if (res) 585 return res; 586 return rpmb_fs_ops.write(ree_fs_rpmb_fh, 0, hash, NULL, sizeof(hash)); 587 } 588 589 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 590 { 591 tee_fs_dirfile_close(*dirh); 592 *dirh = NULL; 593 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 594 } 595 596 #else /*!CFG_REE_FS_INTEGRITY_RPMB*/ 597 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh) 598 { 599 TEE_Result res = TEE_SUCCESS; 600 uint32_t min_counter = 0; 601 602 res = nv_counter_get_ree_fs(&min_counter); 603 if (res) { 604 static bool once; 605 606 if (res != TEE_ERROR_NOT_IMPLEMENTED || 607 !IS_ENABLED(CFG_INSECURE)) 608 return res; 609 610 if (!once) { 611 IMSG("WARNING (insecure configuration): Failed to get monotonic counter for REE FS, using 0"); 612 once = true; 613 } 614 min_counter = 0; 615 } 616 res = tee_fs_dirfile_open(false, NULL, min_counter, &ree_dirf_ops, 617 dirh); 618 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 619 if (min_counter) { 620 if (!IS_ENABLED(CFG_REE_FS_ALLOW_RESET)) { 621 DMSG("dirf.db file not found"); 622 return TEE_ERROR_SECURITY; 623 } 624 DMSG("dirf.db not found, initializing with a non-zero monotonic counter"); 625 } 626 return tee_fs_dirfile_open(true, NULL, min_counter, 627 &ree_dirf_ops, dirh); 628 } 629 630 return res; 631 } 632 633 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 634 { 635 TEE_Result res = TEE_SUCCESS; 636 uint32_t counter = 0; 637 638 res = tee_fs_dirfile_commit_writes(dirh, NULL, &counter); 639 if (res) 640 return res; 641 res = nv_counter_incr_ree_fs_to(counter); 642 if (res == TEE_ERROR_NOT_IMPLEMENTED && IS_ENABLED(CFG_INSECURE)) { 643 static bool once; 644 645 if (!once) { 646 IMSG("WARNING (insecure configuration): Failed to commit dirh counter %"PRIu32, counter); 647 once = true; 648 } 649 return TEE_SUCCESS; 650 } 651 return res; 652 } 653 654 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 655 { 656 tee_fs_dirfile_close(*dirh); 657 *dirh = NULL; 658 } 659 #endif /*!CFG_REE_FS_INTEGRITY_RPMB*/ 660 661 static TEE_Result get_dirh(struct tee_fs_dirfile_dirh **dirh) 662 { 663 if (!ree_fs_dirh) { 664 TEE_Result res = open_dirh(&ree_fs_dirh); 665 666 if (res) { 667 *dirh = NULL; 668 return res; 669 } 670 } 671 ree_fs_dirh_refcount++; 672 assert(ree_fs_dirh); 673 assert(ree_fs_dirh_refcount); 674 *dirh = ree_fs_dirh; 675 return TEE_SUCCESS; 676 } 677 678 static void put_dirh_primitive(bool close) 679 { 680 assert(ree_fs_dirh_refcount); 681 682 /* 683 * During the execution of one of the ree_fs_ops ree_fs_dirh is 684 * guareteed to be a valid pointer. But when the fop has returned 685 * another thread may get an error or something causing that fop 686 * to do a put with close=1. 687 * 688 * For all fops but ree_fs_close() there's a call to get_dirh() to 689 * get a new dirh which will open it again if it was closed before. 690 * But in the ree_fs_close() case there's no call to get_dirh() 691 * only to this function, put_dirh_primitive(), and in this case 692 * ree_fs_dirh may actually be NULL. 693 */ 694 ree_fs_dirh_refcount--; 695 if (ree_fs_dirh && (!ree_fs_dirh_refcount || close)) 696 close_dirh(&ree_fs_dirh); 697 } 698 699 static void put_dirh(struct tee_fs_dirfile_dirh *dirh, bool close) 700 { 701 if (dirh) { 702 assert(dirh == ree_fs_dirh); 703 put_dirh_primitive(close); 704 } 705 } 706 707 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size, 708 struct tee_file_handle **fh) 709 { 710 TEE_Result res; 711 struct tee_fs_dirfile_dirh *dirh = NULL; 712 struct tee_fs_dirfile_fileh dfh; 713 714 mutex_lock(&ree_fs_mutex); 715 716 res = get_dirh(&dirh); 717 if (res != TEE_SUCCESS) 718 goto out; 719 720 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 721 &dfh); 722 if (res != TEE_SUCCESS) 723 goto out; 724 725 res = ree_fs_open_primitive(false, dfh.hash, 0, &po->uuid, &dfh, fh); 726 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 727 /* 728 * If the object isn't found someone has tampered with it, 729 * treat it as corrupt. 730 */ 731 res = TEE_ERROR_CORRUPT_OBJECT; 732 } else if (!res && size) { 733 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 734 735 *size = tee_fs_htree_get_meta(fdp->ht)->length; 736 } 737 738 out: 739 if (res) 740 put_dirh(dirh, true); 741 mutex_unlock(&ree_fs_mutex); 742 743 return res; 744 } 745 746 static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh, 747 struct tee_fs_fd *fdp, struct tee_pobj *po, 748 bool overwrite) 749 { 750 TEE_Result res; 751 bool have_old_dfh = false; 752 struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 }; 753 754 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 755 &old_dfh); 756 if (!overwrite && !res) 757 return TEE_ERROR_ACCESS_CONFLICT; 758 759 if (!res) 760 have_old_dfh = true; 761 762 /* 763 * If old_dfh wasn't found, the idx will be -1 and 764 * tee_fs_dirfile_rename() will allocate a new index. 765 */ 766 fdp->dfh.idx = old_dfh.idx; 767 old_dfh.idx = -1; 768 res = tee_fs_dirfile_rename(dirh, &po->uuid, &fdp->dfh, 769 po->obj_id, po->obj_id_len); 770 if (res) 771 return res; 772 773 res = commit_dirh_writes(dirh); 774 if (res) 775 return res; 776 777 if (have_old_dfh) 778 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &old_dfh); 779 780 return TEE_SUCCESS; 781 } 782 783 static void ree_fs_close(struct tee_file_handle **fh) 784 { 785 if (*fh) { 786 mutex_lock(&ree_fs_mutex); 787 put_dirh_primitive(false); 788 ree_fs_close_primitive(*fh); 789 *fh = NULL; 790 mutex_unlock(&ree_fs_mutex); 791 792 } 793 } 794 795 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite, 796 const void *head, size_t head_size, 797 const void *attr, size_t attr_size, 798 const void *data_core, const void *data_user, 799 size_t data_size, struct tee_file_handle **fh) 800 { 801 struct tee_fs_fd *fdp; 802 struct tee_fs_dirfile_dirh *dirh = NULL; 803 struct tee_fs_dirfile_fileh dfh; 804 TEE_Result res; 805 size_t pos = 0; 806 807 /* One of data_core and data_user must be NULL */ 808 assert(!data_core || !data_user); 809 810 *fh = NULL; 811 mutex_lock(&ree_fs_mutex); 812 813 res = get_dirh(&dirh); 814 if (res) 815 goto out; 816 817 res = tee_fs_dirfile_get_tmp(dirh, &dfh); 818 if (res) 819 goto out; 820 821 res = ree_fs_open_primitive(true, dfh.hash, 0, &po->uuid, &dfh, fh); 822 if (res) 823 goto out; 824 825 if (head && head_size) { 826 res = ree_fs_write_primitive(*fh, pos, head, NULL, head_size); 827 if (res) 828 goto out; 829 pos += head_size; 830 } 831 832 if (attr && attr_size) { 833 res = ree_fs_write_primitive(*fh, pos, attr, NULL, attr_size); 834 if (res) 835 goto out; 836 pos += attr_size; 837 } 838 839 if ((data_core || data_user) && data_size) { 840 res = ree_fs_write_primitive(*fh, pos, data_core, data_user, 841 data_size); 842 if (res) 843 goto out; 844 } 845 846 fdp = (struct tee_fs_fd *)*fh; 847 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, NULL); 848 if (res) 849 goto out; 850 851 res = set_name(dirh, fdp, po, overwrite); 852 out: 853 if (res) { 854 put_dirh(dirh, true); 855 if (*fh) { 856 ree_fs_close_primitive(*fh); 857 *fh = NULL; 858 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh); 859 } 860 } 861 mutex_unlock(&ree_fs_mutex); 862 863 return res; 864 } 865 866 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, 867 const void *buf_core, const void *buf_user, 868 size_t len) 869 { 870 TEE_Result res; 871 struct tee_fs_dirfile_dirh *dirh = NULL; 872 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 873 874 /* One of buf_core and buf_user must be NULL */ 875 assert(!buf_core || !buf_user); 876 877 mutex_lock(&ree_fs_mutex); 878 879 res = get_dirh(&dirh); 880 if (res) 881 goto out; 882 883 res = ree_fs_write_primitive(fh, pos, buf_core, buf_user, len); 884 if (res) 885 goto out; 886 887 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, NULL); 888 if (res) 889 goto out; 890 891 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 892 if (res) 893 goto out; 894 res = commit_dirh_writes(dirh); 895 out: 896 put_dirh(dirh, res); 897 mutex_unlock(&ree_fs_mutex); 898 899 return res; 900 } 901 902 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new, 903 bool overwrite) 904 { 905 TEE_Result res; 906 struct tee_fs_dirfile_dirh *dirh = NULL; 907 struct tee_fs_dirfile_fileh dfh; 908 struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 }; 909 910 if (!new) 911 return TEE_ERROR_BAD_PARAMETERS; 912 913 mutex_lock(&ree_fs_mutex); 914 res = get_dirh(&dirh); 915 if (res) 916 goto out; 917 918 res = tee_fs_dirfile_find(dirh, &new->uuid, new->obj_id, 919 new->obj_id_len, &remove_dfh); 920 if (!res && !overwrite) { 921 res = TEE_ERROR_ACCESS_CONFLICT; 922 goto out; 923 } 924 925 res = tee_fs_dirfile_find(dirh, &old->uuid, old->obj_id, 926 old->obj_id_len, &dfh); 927 if (res) 928 goto out; 929 930 res = tee_fs_dirfile_rename(dirh, &new->uuid, &dfh, new->obj_id, 931 new->obj_id_len); 932 if (res) 933 goto out; 934 935 if (remove_dfh.idx != -1) { 936 res = tee_fs_dirfile_remove(dirh, &remove_dfh); 937 if (res) 938 goto out; 939 } 940 941 res = commit_dirh_writes(dirh); 942 if (res) 943 goto out; 944 945 if (remove_dfh.idx != -1) 946 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &remove_dfh); 947 948 out: 949 put_dirh(dirh, res); 950 mutex_unlock(&ree_fs_mutex); 951 952 return res; 953 954 } 955 956 static TEE_Result ree_fs_remove(struct tee_pobj *po) 957 { 958 TEE_Result res; 959 struct tee_fs_dirfile_dirh *dirh = NULL; 960 struct tee_fs_dirfile_fileh dfh; 961 962 mutex_lock(&ree_fs_mutex); 963 res = get_dirh(&dirh); 964 if (res) 965 goto out; 966 967 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 968 &dfh); 969 if (res) 970 goto out; 971 972 res = tee_fs_dirfile_remove(dirh, &dfh); 973 if (res) 974 goto out; 975 976 res = commit_dirh_writes(dirh); 977 if (res) 978 goto out; 979 980 tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh); 981 982 assert(tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 983 &dfh)); 984 out: 985 put_dirh(dirh, res); 986 mutex_unlock(&ree_fs_mutex); 987 988 return res; 989 } 990 991 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 992 { 993 TEE_Result res; 994 struct tee_fs_dirfile_dirh *dirh = NULL; 995 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 996 997 mutex_lock(&ree_fs_mutex); 998 999 res = get_dirh(&dirh); 1000 if (res) 1001 goto out; 1002 1003 res = ree_fs_ftruncate_internal(fdp, len); 1004 if (res) 1005 goto out; 1006 1007 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, NULL); 1008 if (res) 1009 goto out; 1010 1011 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 1012 if (res) 1013 goto out; 1014 res = commit_dirh_writes(dirh); 1015 out: 1016 put_dirh(dirh, res); 1017 mutex_unlock(&ree_fs_mutex); 1018 1019 return res; 1020 } 1021 1022 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid, 1023 struct tee_fs_dir **dir) 1024 1025 { 1026 TEE_Result res = TEE_SUCCESS; 1027 struct tee_fs_dirfile_dirh *dirh = NULL; 1028 struct tee_fs_dir *d = calloc(1, sizeof(*d)); 1029 1030 if (!d) 1031 return TEE_ERROR_OUT_OF_MEMORY; 1032 1033 d->uuid = uuid; 1034 1035 mutex_lock(&ree_fs_mutex); 1036 1037 res = get_dirh(&dirh); 1038 if (res) 1039 goto out; 1040 1041 /* See that there's at least one file */ 1042 d->idx = -1; 1043 d->d.oidlen = sizeof(d->d.oid); 1044 res = tee_fs_dirfile_get_next(dirh, d->uuid, &d->idx, d->d.oid, 1045 &d->d.oidlen); 1046 d->idx = -1; 1047 1048 out: 1049 if (!res) { 1050 *dir = d; 1051 } else { 1052 if (d) 1053 put_dirh(dirh, false); 1054 free(d); 1055 } 1056 mutex_unlock(&ree_fs_mutex); 1057 1058 return res; 1059 } 1060 1061 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 1062 { 1063 if (d) { 1064 mutex_lock(&ree_fs_mutex); 1065 1066 put_dirh(ree_fs_dirh, false); 1067 free(d); 1068 1069 mutex_unlock(&ree_fs_mutex); 1070 } 1071 } 1072 1073 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 1074 struct tee_fs_dirent **ent) 1075 { 1076 struct tee_fs_dirfile_dirh *dirh = NULL; 1077 TEE_Result res = TEE_SUCCESS; 1078 1079 mutex_lock(&ree_fs_mutex); 1080 1081 res = get_dirh(&dirh); 1082 if (res) 1083 goto out; 1084 1085 d->d.oidlen = sizeof(d->d.oid); 1086 res = tee_fs_dirfile_get_next(dirh, d->uuid, &d->idx, d->d.oid, 1087 &d->d.oidlen); 1088 if (res == TEE_SUCCESS) 1089 *ent = &d->d; 1090 1091 put_dirh(dirh, res); 1092 out: 1093 mutex_unlock(&ree_fs_mutex); 1094 1095 return res; 1096 } 1097 1098 const struct tee_file_operations ree_fs_ops = { 1099 .open = ree_fs_open, 1100 .create = ree_fs_create, 1101 .close = ree_fs_close, 1102 .read = ree_fs_read, 1103 .write = ree_fs_write, 1104 .truncate = ree_fs_truncate, 1105 .rename = ree_fs_rename, 1106 .remove = ree_fs_remove, 1107 .opendir = ree_fs_opendir_rpc, 1108 .closedir = ree_fs_closedir_rpc, 1109 .readdir = ree_fs_readdir_rpc, 1110 }; 1111