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