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 <trace.h> 44 #include <utee_defines.h> 45 #include <util.h> 46 47 #define BLOCK_SHIFT 12 48 49 #define BLOCK_SIZE (1 << BLOCK_SHIFT) 50 51 struct tee_fs_fd { 52 struct tee_fs_htree *ht; 53 tee_fs_off_t pos; 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 char *name, struct tee_fs_dir **d) 65 66 { 67 return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name, d); 68 } 69 70 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 71 { 72 if (d) 73 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d); 74 } 75 76 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 77 struct tee_fs_dirent **ent) 78 { 79 return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent); 80 } 81 82 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, const void *buf, 83 size_t len) 84 { 85 TEE_Result res; 86 size_t start_block_num = pos_to_block_num(fdp->pos); 87 size_t end_block_num = pos_to_block_num(fdp->pos + len - 1); 88 size_t remain_bytes = len; 89 uint8_t *data_ptr = (uint8_t *)buf; 90 uint8_t *block; 91 tee_fs_off_t orig_pos = fdp->pos; 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 int offset = fdp->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 fdp->pos += size_to_write; 130 } 131 132 if (fdp->pos > (tee_fs_off_t)meta->length) 133 meta->length = fdp->pos; 134 135 exit: 136 free(block); 137 if (res != TEE_SUCCESS) 138 fdp->pos = orig_pos; 139 return res; 140 } 141 142 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx, 143 uint8_t vers, size_t *offs, size_t *size) 144 { 145 const size_t node_size = sizeof(struct tee_fs_htree_node_image); 146 const size_t block_nodes = BLOCK_SIZE / (node_size * 2); 147 size_t pbn; 148 size_t bidx; 149 150 assert(vers == 0 || vers == 1); 151 152 /* 153 * File layout 154 * 155 * phys block 0: 156 * tee_fs_htree_image vers 0 @ offs = 0 157 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image) 158 * 159 * phys block 1: 160 * tee_fs_htree_node_image 0 vers 0 @ offs = 0 161 * tee_fs_htree_node_image 0 vers 1 @ offs = node_size 162 * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2 163 * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3 164 * ... 165 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122 166 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123 167 * 168 * phys block 2: 169 * data block 0 vers 0 170 * 171 * phys block 3: 172 * data block 0 vers 1 173 * 174 * ... 175 * phys block 63: 176 * data block 61 vers 0 177 * 178 * phys block 64: 179 * data block 61 vers 1 180 * 181 * phys block 65: 182 * tee_fs_htree_node_image 62 vers 0 @ offs = 0 183 * tee_fs_htree_node_image 62 vers 1 @ offs = node_size 184 * tee_fs_htree_node_image 63 vers 0 @ offs = node_size * 2 185 * tee_fs_htree_node_image 63 vers 1 @ offs = node_size * 3 186 * ... 187 * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122 188 * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123 189 * 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_write_init = ree_fs_rpc_write_init, 256 }; 257 258 static TEE_Result open_internal(const char *file, bool create, 259 struct tee_file_handle **fh) 260 { 261 TEE_Result res; 262 size_t len; 263 struct tee_fs_fd *fdp = NULL; 264 265 if (!file) 266 return TEE_ERROR_BAD_PARAMETERS; 267 268 len = strlen(file) + 1; 269 if (len > TEE_FS_NAME_MAX) 270 return TEE_ERROR_BAD_PARAMETERS; 271 272 fdp = calloc(1, sizeof(struct tee_fs_fd)); 273 if (!fdp) 274 return TEE_ERROR_OUT_OF_MEMORY; 275 fdp->fd = -1; 276 277 mutex_lock(&ree_fs_mutex); 278 279 if (create) 280 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, file, &fdp->fd); 281 else 282 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, file, &fdp->fd); 283 284 if (res != TEE_SUCCESS) 285 goto out; 286 287 res = tee_fs_htree_open(create, &ree_fs_storage_ops, fdp, &fdp->ht); 288 out: 289 if (res == TEE_SUCCESS) { 290 *fh = (struct tee_file_handle *)fdp; 291 } else { 292 if (fdp->fd != -1) 293 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 294 if (create) 295 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file); 296 free(fdp); 297 } 298 299 mutex_unlock(&ree_fs_mutex); 300 return res; 301 } 302 303 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh) 304 { 305 return open_internal(file, false, fh); 306 } 307 308 static TEE_Result ree_fs_create(const char *file, struct tee_file_handle **fh) 309 { 310 return open_internal(file, true, fh); 311 } 312 313 static void ree_fs_close(struct tee_file_handle **fh) 314 { 315 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 316 317 if (fdp) { 318 tee_fs_htree_close(&fdp->ht); 319 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 320 free(fdp); 321 *fh = NULL; 322 } 323 } 324 325 static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset, 326 TEE_Whence whence, int32_t *new_offs) 327 { 328 TEE_Result res; 329 tee_fs_off_t new_pos; 330 size_t filelen; 331 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 332 333 mutex_lock(&ree_fs_mutex); 334 335 filelen = tee_fs_htree_get_meta(fdp->ht)->length; 336 337 switch (whence) { 338 case TEE_DATA_SEEK_SET: 339 new_pos = offset; 340 break; 341 342 case TEE_DATA_SEEK_CUR: 343 new_pos = fdp->pos + offset; 344 break; 345 346 case TEE_DATA_SEEK_END: 347 new_pos = filelen + offset; 348 break; 349 350 default: 351 res = TEE_ERROR_BAD_PARAMETERS; 352 goto exit; 353 } 354 355 if (new_pos < 0) 356 new_pos = 0; 357 358 if (new_pos > TEE_DATA_MAX_POSITION) { 359 EMSG("Position is beyond TEE_DATA_MAX_POSITION"); 360 res = TEE_ERROR_BAD_PARAMETERS; 361 goto exit; 362 } 363 364 fdp->pos = new_pos; 365 if (new_offs) 366 *new_offs = new_pos; 367 res = TEE_SUCCESS; 368 exit: 369 mutex_unlock(&ree_fs_mutex); 370 return res; 371 } 372 373 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, 374 tee_fs_off_t new_file_len) 375 { 376 TEE_Result res; 377 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 378 379 if ((size_t)new_file_len > meta->length) { 380 size_t ext_len = new_file_len - meta->length; 381 int orig_pos = fdp->pos; 382 383 fdp->pos = meta->length; 384 res = out_of_place_write(fdp, NULL, ext_len); 385 fdp->pos = orig_pos; 386 if (res != TEE_SUCCESS) 387 return res; 388 } else { 389 size_t offs; 390 size_t sz; 391 392 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, 393 ROUNDUP(new_file_len, BLOCK_SIZE) / 394 BLOCK_SIZE, 1, &offs, &sz); 395 if (res != TEE_SUCCESS) 396 return res; 397 398 res = tee_fs_htree_truncate(&fdp->ht, 399 new_file_len / BLOCK_SIZE); 400 if (res != TEE_SUCCESS) 401 return res; 402 403 res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd, 404 offs + sz); 405 if (res != TEE_SUCCESS) 406 return res; 407 408 meta->length = new_file_len; 409 } 410 411 return tee_fs_htree_sync_to_storage(&fdp->ht); 412 } 413 414 static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf, 415 size_t *len) 416 { 417 TEE_Result res; 418 int start_block_num; 419 int end_block_num; 420 size_t remain_bytes; 421 uint8_t *data_ptr = buf; 422 uint8_t *block = NULL; 423 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 424 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 425 426 mutex_lock(&ree_fs_mutex); 427 428 remain_bytes = *len; 429 if ((fdp->pos + remain_bytes) < remain_bytes || 430 fdp->pos > (tee_fs_off_t)meta->length) 431 remain_bytes = 0; 432 else if (fdp->pos + (tee_fs_off_t)remain_bytes > 433 (tee_fs_off_t)meta->length) 434 remain_bytes = meta->length - fdp->pos; 435 436 *len = remain_bytes; 437 438 if (!remain_bytes) { 439 res = TEE_SUCCESS; 440 goto exit; 441 } 442 443 start_block_num = pos_to_block_num(fdp->pos); 444 end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1); 445 446 block = malloc(BLOCK_SIZE); 447 if (!block) { 448 res = TEE_ERROR_OUT_OF_MEMORY; 449 goto exit; 450 } 451 452 while (start_block_num <= end_block_num) { 453 tee_fs_off_t offset = fdp->pos % BLOCK_SIZE; 454 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); 455 456 if (size_to_read + offset > BLOCK_SIZE) 457 size_to_read = BLOCK_SIZE - offset; 458 459 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block); 460 if (res != TEE_SUCCESS) 461 goto exit; 462 463 memcpy(data_ptr, block + offset, size_to_read); 464 465 data_ptr += size_to_read; 466 remain_bytes -= size_to_read; 467 fdp->pos += size_to_read; 468 469 start_block_num++; 470 } 471 res = TEE_SUCCESS; 472 exit: 473 mutex_unlock(&ree_fs_mutex); 474 free(block); 475 return res; 476 } 477 478 static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf, 479 size_t len) 480 { 481 TEE_Result res; 482 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 483 size_t file_size; 484 485 if (!len) 486 return TEE_SUCCESS; 487 488 mutex_lock(&ree_fs_mutex); 489 490 file_size = tee_fs_htree_get_meta(fdp->ht)->length; 491 492 if ((fdp->pos + len) < len) { 493 res = TEE_ERROR_BAD_PARAMETERS; 494 goto exit; 495 } 496 497 if (file_size < (size_t)fdp->pos) { 498 res = ree_fs_ftruncate_internal(fdp, fdp->pos); 499 if (res != TEE_SUCCESS) 500 goto exit; 501 } 502 503 res = out_of_place_write(fdp, buf, len); 504 if (res != TEE_SUCCESS) 505 goto exit; 506 507 exit: 508 if (res == TEE_SUCCESS) 509 res = tee_fs_htree_sync_to_storage(&fdp->ht); 510 mutex_unlock(&ree_fs_mutex); 511 return res; 512 } 513 514 static TEE_Result ree_fs_rename(const char *old, const char *new, 515 bool overwrite) 516 { 517 TEE_Result res; 518 519 mutex_lock(&ree_fs_mutex); 520 res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite); 521 mutex_unlock(&ree_fs_mutex); 522 523 return res; 524 } 525 526 static TEE_Result ree_fs_remove(const char *file) 527 { 528 TEE_Result res; 529 530 mutex_lock(&ree_fs_mutex); 531 res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file); 532 mutex_unlock(&ree_fs_mutex); 533 534 return res; 535 } 536 537 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 538 { 539 TEE_Result res; 540 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 541 542 mutex_lock(&ree_fs_mutex); 543 res = ree_fs_ftruncate_internal(fdp, len); 544 mutex_unlock(&ree_fs_mutex); 545 546 return res; 547 } 548 549 const struct tee_file_operations ree_fs_ops = { 550 .open = ree_fs_open, 551 .create = ree_fs_create, 552 .close = ree_fs_close, 553 .read = ree_fs_read, 554 .write = ree_fs_write, 555 .seek = ree_fs_seek, 556 .truncate = ree_fs_truncate, 557 .rename = ree_fs_rename, 558 .remove = ree_fs_remove, 559 .opendir = ree_fs_opendir_rpc, 560 .closedir = ree_fs_closedir_rpc, 561 .readdir = ree_fs_readdir_rpc, 562 }; 563