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