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