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_htree.h> 40 #include <tee/tee_cryp_provider.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 }; 56 57 static int pos_to_block_num(int position) 58 { 59 return position >> BLOCK_SHIFT; 60 } 61 62 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; 63 64 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid, 65 struct tee_fs_dir **d) 66 67 { 68 return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, uuid, d); 69 } 70 71 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 72 { 73 if (d) 74 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d); 75 } 76 77 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 78 struct tee_fs_dirent **ent) 79 { 80 return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent); 81 } 82 83 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos, 84 const void *buf, size_t len) 85 { 86 TEE_Result res; 87 size_t start_block_num = pos_to_block_num(pos); 88 size_t end_block_num = pos_to_block_num(pos + len - 1); 89 size_t remain_bytes = len; 90 uint8_t *data_ptr = (uint8_t *)buf; 91 uint8_t *block; 92 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 93 94 block = malloc(BLOCK_SIZE); 95 if (!block) 96 return TEE_ERROR_OUT_OF_MEMORY; 97 98 while (start_block_num <= end_block_num) { 99 size_t offset = pos % BLOCK_SIZE; 100 size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE); 101 102 if (size_to_write + offset > BLOCK_SIZE) 103 size_to_write = BLOCK_SIZE - offset; 104 105 if (start_block_num * BLOCK_SIZE < 106 ROUNDUP(meta->length, BLOCK_SIZE)) { 107 res = tee_fs_htree_read_block(&fdp->ht, 108 start_block_num, block); 109 if (res != TEE_SUCCESS) 110 goto exit; 111 } else { 112 memset(block, 0, BLOCK_SIZE); 113 } 114 115 if (data_ptr) 116 memcpy(block + offset, data_ptr, size_to_write); 117 else 118 memset(block + offset, 0, size_to_write); 119 120 res = tee_fs_htree_write_block(&fdp->ht, start_block_num, 121 block); 122 if (res != TEE_SUCCESS) 123 goto exit; 124 125 if (data_ptr) 126 data_ptr += size_to_write; 127 remain_bytes -= size_to_write; 128 start_block_num++; 129 pos += size_to_write; 130 } 131 132 if (pos > meta->length) 133 meta->length = pos; 134 135 exit: 136 free(block); 137 return res; 138 } 139 140 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx, 141 uint8_t vers, size_t *offs, size_t *size) 142 { 143 const size_t node_size = sizeof(struct tee_fs_htree_node_image); 144 const size_t block_nodes = BLOCK_SIZE / (node_size * 2); 145 size_t pbn; 146 size_t bidx; 147 148 assert(vers == 0 || vers == 1); 149 150 /* 151 * File layout 152 * 153 * phys block 0: 154 * tee_fs_htree_image vers 0 @ offs = 0 155 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image) 156 * 157 * phys block 1: 158 * tee_fs_htree_node_image 0 vers 0 @ offs = 0 159 * tee_fs_htree_node_image 0 vers 1 @ offs = node_size 160 * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2 161 * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3 162 * ... 163 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122 164 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123 165 * 166 * phys block 2: 167 * data block 0 vers 0 168 * 169 * phys block 3: 170 * data block 0 vers 1 171 * 172 * ... 173 * phys block 63: 174 * data block 61 vers 0 175 * 176 * phys block 64: 177 * data block 61 vers 1 178 * 179 * phys block 65: 180 * tee_fs_htree_node_image 62 vers 0 @ offs = 0 181 * tee_fs_htree_node_image 62 vers 1 @ offs = node_size 182 * tee_fs_htree_node_image 63 vers 0 @ offs = node_size * 2 183 * tee_fs_htree_node_image 63 vers 1 @ offs = node_size * 3 184 * ... 185 * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122 186 * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123 187 * 188 * ... 189 */ 190 191 switch (type) { 192 case TEE_FS_HTREE_TYPE_HEAD: 193 *offs = sizeof(struct tee_fs_htree_image) * vers; 194 *size = sizeof(struct tee_fs_htree_image); 195 return TEE_SUCCESS; 196 case TEE_FS_HTREE_TYPE_NODE: 197 pbn = 1 + ((idx / block_nodes) * block_nodes * 2); 198 *offs = pbn * BLOCK_SIZE + 199 2 * node_size * (idx % block_nodes) + 200 node_size * vers; 201 *size = node_size; 202 return TEE_SUCCESS; 203 case TEE_FS_HTREE_TYPE_BLOCK: 204 bidx = 2 * idx + vers; 205 pbn = 2 + bidx + bidx / (block_nodes * 2 - 1); 206 *offs = pbn * BLOCK_SIZE; 207 *size = BLOCK_SIZE; 208 return TEE_SUCCESS; 209 default: 210 return TEE_ERROR_GENERIC; 211 } 212 } 213 214 static TEE_Result ree_fs_rpc_read_init(void *aux, 215 struct tee_fs_rpc_operation *op, 216 enum tee_fs_htree_type type, size_t idx, 217 uint8_t vers, void **data) 218 { 219 struct tee_fs_fd *fdp = aux; 220 TEE_Result res; 221 size_t offs; 222 size_t size; 223 224 res = get_offs_size(type, idx, vers, &offs, &size); 225 if (res != TEE_SUCCESS) 226 return res; 227 228 return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 229 offs, size, data); 230 } 231 232 static TEE_Result ree_fs_rpc_write_init(void *aux, 233 struct tee_fs_rpc_operation *op, 234 enum tee_fs_htree_type type, size_t idx, 235 uint8_t vers, void **data) 236 { 237 struct tee_fs_fd *fdp = aux; 238 TEE_Result res; 239 size_t offs; 240 size_t size; 241 242 res = get_offs_size(type, idx, vers, &offs, &size); 243 if (res != TEE_SUCCESS) 244 return res; 245 246 return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 247 offs, size, data); 248 } 249 250 static const struct tee_fs_htree_storage ree_fs_storage_ops = { 251 .block_size = BLOCK_SIZE, 252 .rpc_read_init = ree_fs_rpc_read_init, 253 .rpc_read_final = tee_fs_rpc_read_final, 254 .rpc_write_init = ree_fs_rpc_write_init, 255 .rpc_write_final = tee_fs_rpc_write_final, 256 }; 257 258 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, 259 tee_fs_off_t new_file_len) 260 { 261 TEE_Result res; 262 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 263 264 if ((size_t)new_file_len > meta->length) { 265 size_t ext_len = new_file_len - meta->length; 266 267 res = out_of_place_write(fdp, meta->length, NULL, ext_len); 268 if (res != TEE_SUCCESS) 269 return res; 270 } else { 271 size_t offs; 272 size_t sz; 273 274 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, 275 ROUNDUP(new_file_len, BLOCK_SIZE) / 276 BLOCK_SIZE, 1, &offs, &sz); 277 if (res != TEE_SUCCESS) 278 return res; 279 280 res = tee_fs_htree_truncate(&fdp->ht, 281 new_file_len / BLOCK_SIZE); 282 if (res != TEE_SUCCESS) 283 return res; 284 285 res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd, 286 offs + sz); 287 if (res != TEE_SUCCESS) 288 return res; 289 290 meta->length = new_file_len; 291 } 292 293 return tee_fs_htree_sync_to_storage(&fdp->ht); 294 } 295 296 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos, 297 void *buf, size_t *len) 298 { 299 TEE_Result res; 300 int start_block_num; 301 int end_block_num; 302 size_t remain_bytes; 303 uint8_t *data_ptr = buf; 304 uint8_t *block = NULL; 305 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 306 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 307 308 mutex_lock(&ree_fs_mutex); 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 mutex_unlock(&ree_fs_mutex); 354 free(block); 355 return res; 356 } 357 358 static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos, 359 const void *buf, size_t len) 360 { 361 TEE_Result res; 362 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 363 size_t file_size; 364 365 if (!len) 366 return TEE_SUCCESS; 367 368 file_size = tee_fs_htree_get_meta(fdp->ht)->length; 369 370 if ((pos + len) < len) 371 return TEE_ERROR_BAD_PARAMETERS; 372 373 if (file_size < pos) { 374 res = ree_fs_ftruncate_internal(fdp, pos); 375 if (res != TEE_SUCCESS) 376 return res; 377 } 378 379 return out_of_place_write(fdp, pos, buf, len); 380 } 381 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, 382 const void *buf, size_t len) 383 { 384 TEE_Result res; 385 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 386 387 mutex_lock(&ree_fs_mutex); 388 389 res = ree_fs_write_primitive(fh, pos, buf, len); 390 391 if (res == TEE_SUCCESS) 392 res = tee_fs_htree_sync_to_storage(&fdp->ht); 393 394 mutex_unlock(&ree_fs_mutex); 395 396 return res; 397 } 398 399 static TEE_Result open_internal(struct tee_pobj *po, bool create, 400 struct tee_file_handle **fh) 401 { 402 TEE_Result res; 403 struct tee_fs_fd *fdp = NULL; 404 405 fdp = calloc(1, sizeof(struct tee_fs_fd)); 406 if (!fdp) 407 return TEE_ERROR_OUT_OF_MEMORY; 408 fdp->fd = -1; 409 410 if (create) 411 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd); 412 else 413 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd); 414 415 if (res != TEE_SUCCESS) 416 goto out; 417 418 res = tee_fs_htree_open(create, &ree_fs_storage_ops, fdp, &fdp->ht); 419 out: 420 if (res == TEE_SUCCESS) { 421 *fh = (struct tee_file_handle *)fdp; 422 } else { 423 if (fdp->fd != -1) 424 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 425 if (create) 426 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po); 427 free(fdp); 428 } 429 430 return res; 431 } 432 433 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size, 434 struct tee_file_handle **fh) 435 { 436 TEE_Result res; 437 438 mutex_lock(&ree_fs_mutex); 439 res = open_internal(po, false, fh); 440 if (!res && size) { 441 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 442 443 *size = tee_fs_htree_get_meta(fdp->ht)->length; 444 } 445 mutex_unlock(&ree_fs_mutex); 446 447 return res; 448 } 449 450 static void ree_fs_close(struct tee_file_handle **fh) 451 { 452 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 453 454 if (fdp) { 455 tee_fs_htree_close(&fdp->ht); 456 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 457 free(fdp); 458 *fh = NULL; 459 } 460 } 461 462 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite, 463 const void *head, size_t head_size, 464 const void *attr, size_t attr_size, 465 const void *data, size_t data_size, 466 struct tee_file_handle **fh) 467 { 468 struct tee_fs_fd *fdp; 469 TEE_Result res; 470 size_t pos = 0; 471 472 *fh = NULL; 473 mutex_lock(&ree_fs_mutex); 474 475 res = open_internal(po, true, fh); 476 if (res) 477 goto out; 478 479 if (head && head_size) { 480 res = ree_fs_write_primitive(*fh, pos, head, head_size); 481 if (res) 482 goto out; 483 pos += head_size; 484 } 485 486 if (attr && attr_size) { 487 res = ree_fs_write_primitive(*fh, pos, attr, attr_size); 488 if (res) 489 goto out; 490 pos += attr_size; 491 } 492 493 if (data && data_size) { 494 res = ree_fs_write_primitive(*fh, pos, data, data_size); 495 if (res) 496 goto out; 497 } 498 499 fdp = (struct tee_fs_fd *)*fh; 500 res = tee_fs_htree_sync_to_storage(&fdp->ht); 501 if (res) 502 goto out; 503 504 if (po->temporary) { 505 /* 506 * If it's a temporary filename (which it normally is) 507 * rename into the final filename now that the file is 508 * fully initialized. 509 */ 510 po->temporary = false; 511 res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, po, NULL, 512 overwrite); 513 if (res) 514 po->temporary = true; 515 } 516 out: 517 if (res && *fh) { 518 ree_fs_close(fh); 519 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po); 520 } 521 522 mutex_unlock(&ree_fs_mutex); 523 524 return res; 525 } 526 527 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new, 528 bool overwrite) 529 { 530 TEE_Result res; 531 532 mutex_lock(&ree_fs_mutex); 533 res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite); 534 mutex_unlock(&ree_fs_mutex); 535 536 return res; 537 } 538 539 static TEE_Result ree_fs_remove(struct tee_pobj *po) 540 { 541 TEE_Result res; 542 543 mutex_lock(&ree_fs_mutex); 544 res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po); 545 mutex_unlock(&ree_fs_mutex); 546 547 return res; 548 } 549 550 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 551 { 552 TEE_Result res; 553 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 554 555 mutex_lock(&ree_fs_mutex); 556 res = ree_fs_ftruncate_internal(fdp, len); 557 mutex_unlock(&ree_fs_mutex); 558 559 return res; 560 } 561 562 const struct tee_file_operations ree_fs_ops = { 563 .open = ree_fs_open, 564 .create = ree_fs_create, 565 .close = ree_fs_close, 566 .read = ree_fs_read, 567 .write = ree_fs_write, 568 .truncate = ree_fs_truncate, 569 .rename = ree_fs_rename, 570 .remove = ree_fs_remove, 571 .opendir = ree_fs_opendir_rpc, 572 .closedir = ree_fs_closedir_rpc, 573 .readdir = ree_fs_readdir_rpc, 574 }; 575