1 /* 2 * Copyright (c) 2015, Linaro Limited 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 <assert.h> 29 #include <kernel/mutex.h> 30 #include <kernel/panic.h> 31 #include <kernel/thread.h> 32 #include <mm/core_memprot.h> 33 #include <optee_msg_supplicant.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string_ext.h> 37 #include <string.h> 38 #include <sys/queue.h> 39 #include <tee/fs_dirfile.h> 40 #include <tee/fs_htree.h> 41 #include <tee/tee_fs.h> 42 #include <tee/tee_fs_rpc.h> 43 #include <tee/tee_pobj.h> 44 #include <trace.h> 45 #include <utee_defines.h> 46 #include <util.h> 47 48 #define BLOCK_SHIFT 12 49 50 #define BLOCK_SIZE (1 << BLOCK_SHIFT) 51 52 struct tee_fs_fd { 53 struct tee_fs_htree *ht; 54 int fd; 55 struct tee_fs_dirfile_fileh dfh; 56 const TEE_UUID *uuid; 57 }; 58 59 struct tee_fs_dir { 60 struct tee_fs_dirfile_dirh *dirh; 61 int idx; 62 struct tee_fs_dirent d; 63 const TEE_UUID *uuid; 64 }; 65 66 static int pos_to_block_num(int position) 67 { 68 return position >> BLOCK_SHIFT; 69 } 70 71 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; 72 73 74 75 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos, 76 const void *buf, size_t len) 77 { 78 TEE_Result res; 79 size_t start_block_num = pos_to_block_num(pos); 80 size_t end_block_num = pos_to_block_num(pos + len - 1); 81 size_t remain_bytes = len; 82 uint8_t *data_ptr = (uint8_t *)buf; 83 uint8_t *block; 84 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 85 86 block = malloc(BLOCK_SIZE); 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_ptr) 108 memcpy(block + offset, data_ptr, size_to_write); 109 else 110 memset(block + offset, 0, size_to_write); 111 112 res = tee_fs_htree_write_block(&fdp->ht, start_block_num, 113 block); 114 if (res != TEE_SUCCESS) 115 goto exit; 116 117 if (data_ptr) 118 data_ptr += size_to_write; 119 remain_bytes -= size_to_write; 120 start_block_num++; 121 pos += size_to_write; 122 } 123 124 if (pos > meta->length) 125 meta->length = pos; 126 127 exit: 128 free(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_MSG_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_MSG_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_MSG_RPC_CMD_FS, fdp->fd, 287 offs + sz); 288 if (res != TEE_SUCCESS) 289 return res; 290 291 meta->length = new_file_len; 292 } 293 294 return TEE_SUCCESS; 295 } 296 297 static TEE_Result ree_fs_read_primitive(struct tee_file_handle *fh, size_t pos, 298 void *buf, size_t *len) 299 { 300 TEE_Result res; 301 int start_block_num; 302 int end_block_num; 303 size_t remain_bytes; 304 uint8_t *data_ptr = buf; 305 uint8_t *block = NULL; 306 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 307 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 308 309 remain_bytes = *len; 310 if ((pos + remain_bytes) < remain_bytes || pos > meta->length) 311 remain_bytes = 0; 312 else if (pos + remain_bytes > meta->length) 313 remain_bytes = meta->length - pos; 314 315 *len = remain_bytes; 316 317 if (!remain_bytes) { 318 res = TEE_SUCCESS; 319 goto exit; 320 } 321 322 start_block_num = pos_to_block_num(pos); 323 end_block_num = pos_to_block_num(pos + remain_bytes - 1); 324 325 block = malloc(BLOCK_SIZE); 326 if (!block) { 327 res = TEE_ERROR_OUT_OF_MEMORY; 328 goto exit; 329 } 330 331 while (start_block_num <= end_block_num) { 332 size_t offset = pos % BLOCK_SIZE; 333 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); 334 335 if (size_to_read + offset > BLOCK_SIZE) 336 size_to_read = BLOCK_SIZE - offset; 337 338 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block); 339 if (res != TEE_SUCCESS) 340 goto exit; 341 342 memcpy(data_ptr, block + offset, size_to_read); 343 344 data_ptr += size_to_read; 345 remain_bytes -= size_to_read; 346 pos += size_to_read; 347 348 start_block_num++; 349 } 350 res = TEE_SUCCESS; 351 exit: 352 free(block); 353 return res; 354 } 355 356 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos, 357 void *buf, size_t *len) 358 { 359 TEE_Result res; 360 361 mutex_lock(&ree_fs_mutex); 362 res = ree_fs_read_primitive(fh, pos, buf, len); 363 mutex_unlock(&ree_fs_mutex); 364 365 return res; 366 } 367 368 static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos, 369 const void *buf, size_t len) 370 { 371 TEE_Result res; 372 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 373 size_t file_size; 374 375 if (!len) 376 return TEE_SUCCESS; 377 378 file_size = tee_fs_htree_get_meta(fdp->ht)->length; 379 380 if ((pos + len) < len) 381 return TEE_ERROR_BAD_PARAMETERS; 382 383 if (file_size < pos) { 384 res = ree_fs_ftruncate_internal(fdp, pos); 385 if (res != TEE_SUCCESS) 386 return res; 387 } 388 389 return out_of_place_write(fdp, pos, buf, len); 390 } 391 392 static TEE_Result ree_fs_open_primitive(bool create, uint8_t *hash, 393 const TEE_UUID *uuid, 394 struct tee_fs_dirfile_fileh *dfh, 395 struct tee_file_handle **fh) 396 { 397 TEE_Result res; 398 struct tee_fs_fd *fdp; 399 400 fdp = calloc(1, sizeof(struct tee_fs_fd)); 401 if (!fdp) 402 return TEE_ERROR_OUT_OF_MEMORY; 403 fdp->fd = -1; 404 fdp->uuid = uuid; 405 406 if (create) 407 res = tee_fs_rpc_create_dfh(OPTEE_MSG_RPC_CMD_FS, 408 dfh, &fdp->fd); 409 else 410 res = tee_fs_rpc_open_dfh(OPTEE_MSG_RPC_CMD_FS, dfh, &fdp->fd); 411 412 if (res != TEE_SUCCESS) 413 goto out; 414 415 res = tee_fs_htree_open(create, hash, uuid, &ree_fs_storage_ops, 416 fdp, &fdp->ht); 417 out: 418 if (res == TEE_SUCCESS) { 419 if (dfh) 420 fdp->dfh = *dfh; 421 else 422 fdp->dfh.idx = -1; 423 *fh = (struct tee_file_handle *)fdp; 424 } else { 425 if (fdp->fd != -1) 426 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 427 if (create) 428 tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, dfh); 429 free(fdp); 430 } 431 432 return res; 433 } 434 435 static void ree_fs_close_primitive(struct tee_file_handle *fh) 436 { 437 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 438 439 if (fdp) { 440 tee_fs_htree_close(&fdp->ht); 441 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 442 free(fdp); 443 } 444 } 445 446 static TEE_Result ree_dirf_commit_writes(struct tee_file_handle *fh, 447 uint8_t *hash) 448 { 449 TEE_Result res; 450 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 451 452 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 453 454 if (!res && hash) 455 memcpy(hash, fdp->dfh.hash, sizeof(fdp->dfh.hash)); 456 457 return res; 458 } 459 460 static const struct tee_fs_dirfile_operations ree_dirf_ops = { 461 .open = ree_fs_open_primitive, 462 .close = ree_fs_close_primitive, 463 .read = ree_fs_read_primitive, 464 .write = ree_fs_write_primitive, 465 .commit_writes = ree_dirf_commit_writes, 466 }; 467 468 static struct tee_fs_dirfile_dirh *ree_fs_dirh; 469 static size_t ree_fs_dirh_refcount; 470 471 #ifdef CFG_RPMB_FS 472 static struct tee_file_handle *ree_fs_rpmb_fh; 473 474 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh) 475 { 476 TEE_Result res; 477 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 478 uint8_t *hashp = NULL; 479 const char fname[] = "dirfile.db.hash"; 480 481 res = tee_rpmb_fs_raw_open(fname, false, &ree_fs_rpmb_fh); 482 if (!res) { 483 size_t l = sizeof(hash); 484 485 res = rpmb_fs_ops.read(ree_fs_rpmb_fh, 0, hash, &l); 486 if (res) 487 return res; 488 if (l == sizeof(hash)) 489 hashp = hash; 490 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 491 res = tee_rpmb_fs_raw_open(fname, true, &ree_fs_rpmb_fh); 492 } 493 if (res) 494 return res; 495 496 if (!tee_fs_dirfile_open(false, hashp, &ree_dirf_ops, dirh)) 497 return TEE_SUCCESS; 498 499 res = tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh); 500 if (res) 501 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 502 return res; 503 } 504 505 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 506 { 507 TEE_Result res; 508 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 509 510 res = tee_fs_dirfile_commit_writes(dirh, hash); 511 if (res) 512 return res; 513 return rpmb_fs_ops.write(ree_fs_rpmb_fh, 0, hash, sizeof(hash)); 514 } 515 516 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 517 { 518 tee_fs_dirfile_close(*dirh); 519 *dirh = NULL; 520 rpmb_fs_ops.close(&ree_fs_rpmb_fh); 521 } 522 523 #else /*!CFG_RPMB_FS*/ 524 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh) 525 { 526 if (!tee_fs_dirfile_open(false, NULL, &ree_dirf_ops, dirh)) 527 return TEE_SUCCESS; 528 return tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh); 529 } 530 531 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh) 532 { 533 return tee_fs_dirfile_commit_writes(dirh, NULL); 534 } 535 536 static void close_dirh(struct tee_fs_dirfile_dirh **dirh) 537 { 538 tee_fs_dirfile_close(*dirh); 539 *dirh = NULL; 540 } 541 #endif /*!CFG_RPMB_FS*/ 542 543 static TEE_Result get_dirh(struct tee_fs_dirfile_dirh **dirh) 544 { 545 if (!ree_fs_dirh) { 546 TEE_Result res = open_dirh(&ree_fs_dirh); 547 548 if (res) { 549 *dirh = NULL; 550 return res; 551 } 552 } 553 ree_fs_dirh_refcount++; 554 assert(ree_fs_dirh); 555 assert(ree_fs_dirh_refcount); 556 *dirh = ree_fs_dirh; 557 return TEE_SUCCESS; 558 } 559 560 static void put_dirh_primitive(bool close) 561 { 562 assert(ree_fs_dirh_refcount); 563 564 /* 565 * During the execution of one of the ree_fs_ops ree_fs_dirh is 566 * guareteed to be a valid pointer. But when the fop has returned 567 * another thread may get an error or something causing that fop 568 * to do a put with close=1. 569 * 570 * For all fops but ree_fs_close() there's a call to get_dirh() to 571 * get a new dirh which will open it again if it was closed before. 572 * But in the ree_fs_close() case there's no call to get_dirh() 573 * only to this function, put_dirh_primitive(), and in this case 574 * ree_fs_dirh may actually be NULL. 575 */ 576 ree_fs_dirh_refcount--; 577 if (ree_fs_dirh && (!ree_fs_dirh_refcount || close)) 578 close_dirh(&ree_fs_dirh); 579 } 580 581 static void put_dirh(struct tee_fs_dirfile_dirh *dirh, bool close) 582 { 583 if (dirh) { 584 assert(dirh == ree_fs_dirh); 585 put_dirh_primitive(close); 586 } 587 } 588 589 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size, 590 struct tee_file_handle **fh) 591 { 592 TEE_Result res; 593 struct tee_fs_dirfile_dirh *dirh = NULL; 594 struct tee_fs_dirfile_fileh dfh; 595 596 mutex_lock(&ree_fs_mutex); 597 598 res = get_dirh(&dirh); 599 if (res != TEE_SUCCESS) 600 goto out; 601 602 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 603 &dfh); 604 if (res != TEE_SUCCESS) 605 goto out; 606 607 res = ree_fs_open_primitive(false, dfh.hash, &po->uuid, &dfh, fh); 608 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 609 /* 610 * If the object isn't found someone has tampered with it, 611 * treat it as corrupt. 612 */ 613 res = TEE_ERROR_CORRUPT_OBJECT; 614 } else if (!res && size) { 615 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 616 617 *size = tee_fs_htree_get_meta(fdp->ht)->length; 618 } 619 620 out: 621 if (res) 622 put_dirh(dirh, false); 623 mutex_unlock(&ree_fs_mutex); 624 625 return res; 626 } 627 628 static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh, 629 struct tee_fs_fd *fdp, struct tee_pobj *po, 630 bool overwrite) 631 { 632 TEE_Result res; 633 bool have_old_dfh = false; 634 struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 }; 635 636 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 637 &old_dfh); 638 if (!overwrite && !res) 639 return TEE_ERROR_ACCESS_CONFLICT; 640 641 if (!res) 642 have_old_dfh = true; 643 644 /* 645 * If old_dfh wasn't found, the idx will be -1 and 646 * tee_fs_dirfile_rename() will allocate a new index. 647 */ 648 fdp->dfh.idx = old_dfh.idx; 649 old_dfh.idx = -1; 650 res = tee_fs_dirfile_rename(dirh, &po->uuid, &fdp->dfh, 651 po->obj_id, po->obj_id_len); 652 if (res) 653 return res; 654 655 res = commit_dirh_writes(dirh); 656 if (res) 657 return res; 658 659 if (have_old_dfh) 660 tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &old_dfh); 661 662 return TEE_SUCCESS; 663 } 664 665 static void ree_fs_close(struct tee_file_handle **fh) 666 { 667 if (*fh) { 668 mutex_lock(&ree_fs_mutex); 669 put_dirh_primitive(false); 670 mutex_unlock(&ree_fs_mutex); 671 672 ree_fs_close_primitive(*fh); 673 *fh = NULL; 674 } 675 } 676 677 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite, 678 const void *head, size_t head_size, 679 const void *attr, size_t attr_size, 680 const void *data, size_t data_size, 681 struct tee_file_handle **fh) 682 { 683 struct tee_fs_fd *fdp; 684 struct tee_fs_dirfile_dirh *dirh = NULL; 685 struct tee_fs_dirfile_fileh dfh; 686 TEE_Result res; 687 size_t pos = 0; 688 689 *fh = NULL; 690 mutex_lock(&ree_fs_mutex); 691 692 res = get_dirh(&dirh); 693 if (res) 694 goto out; 695 696 res = tee_fs_dirfile_get_tmp(dirh, &dfh); 697 if (res) 698 goto out; 699 700 res = ree_fs_open_primitive(true, dfh.hash, &po->uuid, &dfh, fh); 701 if (res) 702 goto out; 703 704 if (head && head_size) { 705 res = ree_fs_write_primitive(*fh, pos, head, head_size); 706 if (res) 707 goto out; 708 pos += head_size; 709 } 710 711 if (attr && attr_size) { 712 res = ree_fs_write_primitive(*fh, pos, attr, attr_size); 713 if (res) 714 goto out; 715 pos += attr_size; 716 } 717 718 if (data && data_size) { 719 res = ree_fs_write_primitive(*fh, pos, data, data_size); 720 if (res) 721 goto out; 722 } 723 724 fdp = (struct tee_fs_fd *)*fh; 725 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 726 if (res) 727 goto out; 728 729 res = set_name(dirh, fdp, po, overwrite); 730 out: 731 if (res) { 732 put_dirh(dirh, true); 733 if (*fh) { 734 ree_fs_close_primitive(*fh); 735 *fh = NULL; 736 tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh); 737 } 738 } 739 mutex_unlock(&ree_fs_mutex); 740 741 return res; 742 } 743 744 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, 745 const void *buf, size_t len) 746 { 747 TEE_Result res; 748 struct tee_fs_dirfile_dirh *dirh = NULL; 749 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 750 751 mutex_lock(&ree_fs_mutex); 752 753 res = get_dirh(&dirh); 754 if (res) 755 goto out; 756 757 res = ree_fs_write_primitive(fh, pos, buf, len); 758 if (res) 759 goto out; 760 761 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 762 if (res) 763 goto out; 764 765 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 766 if (res) 767 goto out; 768 res = commit_dirh_writes(dirh); 769 out: 770 put_dirh(dirh, res); 771 mutex_unlock(&ree_fs_mutex); 772 773 return res; 774 } 775 776 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new, 777 bool overwrite) 778 { 779 TEE_Result res; 780 struct tee_fs_dirfile_dirh *dirh = NULL; 781 struct tee_fs_dirfile_fileh dfh; 782 struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 }; 783 784 if (!new) 785 return TEE_ERROR_BAD_PARAMETERS; 786 787 mutex_lock(&ree_fs_mutex); 788 res = get_dirh(&dirh); 789 if (res) 790 goto out; 791 792 res = tee_fs_dirfile_find(dirh, &new->uuid, new->obj_id, 793 new->obj_id_len, &remove_dfh); 794 if (!res && !overwrite) { 795 res = TEE_ERROR_ACCESS_CONFLICT; 796 goto out; 797 } 798 799 res = tee_fs_dirfile_find(dirh, &old->uuid, old->obj_id, 800 old->obj_id_len, &dfh); 801 if (res) 802 goto out; 803 804 res = tee_fs_dirfile_rename(dirh, &new->uuid, &dfh, new->obj_id, 805 new->obj_id_len); 806 if (res) 807 goto out; 808 809 if (remove_dfh.idx != -1) { 810 res = tee_fs_dirfile_remove(dirh, &remove_dfh); 811 if (res) 812 goto out; 813 } 814 815 res = commit_dirh_writes(dirh); 816 if (res) 817 goto out; 818 819 if (remove_dfh.idx != -1) 820 tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &remove_dfh); 821 822 out: 823 put_dirh(dirh, res); 824 mutex_unlock(&ree_fs_mutex); 825 826 return res; 827 828 } 829 830 static TEE_Result ree_fs_remove(struct tee_pobj *po) 831 { 832 TEE_Result res; 833 struct tee_fs_dirfile_dirh *dirh = NULL; 834 struct tee_fs_dirfile_fileh dfh; 835 836 mutex_lock(&ree_fs_mutex); 837 res = get_dirh(&dirh); 838 if (res) 839 goto out; 840 841 res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 842 &dfh); 843 if (res) 844 goto out; 845 846 res = tee_fs_dirfile_remove(dirh, &dfh); 847 if (res) 848 goto out; 849 850 res = commit_dirh_writes(dirh); 851 if (res) 852 goto out; 853 854 tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh); 855 856 assert(tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len, 857 &dfh)); 858 out: 859 put_dirh(dirh, res); 860 mutex_unlock(&ree_fs_mutex); 861 862 return res; 863 } 864 865 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 866 { 867 TEE_Result res; 868 struct tee_fs_dirfile_dirh *dirh = NULL; 869 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 870 871 mutex_lock(&ree_fs_mutex); 872 873 res = get_dirh(&dirh); 874 if (res != TEE_SUCCESS) 875 goto out; 876 877 res = ree_fs_ftruncate_internal(fdp, len); 878 if (!res) 879 goto out; 880 881 res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash); 882 if (!res) 883 goto out; 884 885 res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh); 886 887 out: 888 put_dirh(dirh, res); 889 mutex_unlock(&ree_fs_mutex); 890 891 return res; 892 } 893 894 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid, 895 struct tee_fs_dir **dir) 896 897 { 898 TEE_Result res; 899 struct tee_fs_dir *d = calloc(1, sizeof(*d)); 900 901 if (!d) 902 return TEE_ERROR_OUT_OF_MEMORY; 903 904 d->uuid = uuid; 905 906 mutex_lock(&ree_fs_mutex); 907 908 res = get_dirh(&d->dirh); 909 if (res) 910 goto out; 911 912 /* See that there's at least one file */ 913 d->idx = -1; 914 d->d.oidlen = sizeof(d->d.oid); 915 res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid, 916 &d->d.oidlen); 917 d->idx = -1; 918 919 out: 920 if (!res) { 921 *dir = d; 922 } else { 923 if (d) 924 put_dirh(d->dirh, false); 925 free(d); 926 } 927 mutex_unlock(&ree_fs_mutex); 928 929 return res; 930 } 931 932 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 933 { 934 if (d) { 935 mutex_lock(&ree_fs_mutex); 936 937 put_dirh(d->dirh, false); 938 free(d); 939 940 mutex_unlock(&ree_fs_mutex); 941 } 942 } 943 944 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 945 struct tee_fs_dirent **ent) 946 { 947 TEE_Result res; 948 949 mutex_lock(&ree_fs_mutex); 950 951 d->d.oidlen = sizeof(d->d.oid); 952 res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid, 953 &d->d.oidlen); 954 if (res == TEE_SUCCESS) 955 *ent = &d->d; 956 957 mutex_unlock(&ree_fs_mutex); 958 959 return res; 960 } 961 962 const struct tee_file_operations ree_fs_ops = { 963 .open = ree_fs_open, 964 .create = ree_fs_create, 965 .close = ree_fs_close, 966 .read = ree_fs_read, 967 .write = ree_fs_write, 968 .truncate = ree_fs_truncate, 969 .rename = ree_fs_rename, 970 .remove = ree_fs_remove, 971 .opendir = ree_fs_opendir_rpc, 972 .closedir = ree_fs_closedir_rpc, 973 .readdir = ree_fs_readdir_rpc, 974 }; 975