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