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 int fd; 54 }; 55 56 static int pos_to_block_num(int position) 57 { 58 return position >> BLOCK_SHIFT; 59 } 60 61 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; 62 63 static TEE_Result ree_fs_opendir_rpc(const char *name, struct tee_fs_dir **d) 64 65 { 66 return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name, d); 67 } 68 69 static void ree_fs_closedir_rpc(struct tee_fs_dir *d) 70 { 71 if (d) 72 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d); 73 } 74 75 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, 76 struct tee_fs_dirent **ent) 77 { 78 return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent); 79 } 80 81 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos, 82 const void *buf, size_t len) 83 { 84 TEE_Result res; 85 size_t start_block_num = pos_to_block_num(pos); 86 size_t end_block_num = pos_to_block_num(pos + len - 1); 87 size_t remain_bytes = len; 88 uint8_t *data_ptr = (uint8_t *)buf; 89 uint8_t *block; 90 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 91 92 block = malloc(BLOCK_SIZE); 93 if (!block) 94 return TEE_ERROR_OUT_OF_MEMORY; 95 96 while (start_block_num <= end_block_num) { 97 size_t offset = pos % BLOCK_SIZE; 98 size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE); 99 100 if (size_to_write + offset > BLOCK_SIZE) 101 size_to_write = BLOCK_SIZE - offset; 102 103 if (start_block_num * BLOCK_SIZE < 104 ROUNDUP(meta->length, BLOCK_SIZE)) { 105 res = tee_fs_htree_read_block(&fdp->ht, 106 start_block_num, block); 107 if (res != TEE_SUCCESS) 108 goto exit; 109 } else { 110 memset(block, 0, BLOCK_SIZE); 111 } 112 113 if (data_ptr) 114 memcpy(block + offset, data_ptr, size_to_write); 115 else 116 memset(block + offset, 0, size_to_write); 117 118 res = tee_fs_htree_write_block(&fdp->ht, start_block_num, 119 block); 120 if (res != TEE_SUCCESS) 121 goto exit; 122 123 if (data_ptr) 124 data_ptr += size_to_write; 125 remain_bytes -= size_to_write; 126 start_block_num++; 127 pos += size_to_write; 128 } 129 130 if (pos > meta->length) 131 meta->length = pos; 132 133 exit: 134 free(block); 135 return res; 136 } 137 138 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx, 139 uint8_t vers, size_t *offs, size_t *size) 140 { 141 const size_t node_size = sizeof(struct tee_fs_htree_node_image); 142 const size_t block_nodes = BLOCK_SIZE / (node_size * 2); 143 size_t pbn; 144 size_t bidx; 145 146 assert(vers == 0 || vers == 1); 147 148 /* 149 * File layout 150 * 151 * phys block 0: 152 * tee_fs_htree_image vers 0 @ offs = 0 153 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image) 154 * 155 * phys block 1: 156 * tee_fs_htree_node_image 0 vers 0 @ offs = 0 157 * tee_fs_htree_node_image 0 vers 1 @ offs = node_size 158 * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2 159 * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3 160 * ... 161 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122 162 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123 163 * 164 * phys block 2: 165 * data block 0 vers 0 166 * 167 * phys block 3: 168 * data block 0 vers 1 169 * 170 * ... 171 * phys block 63: 172 * data block 61 vers 0 173 * 174 * phys block 64: 175 * data block 61 vers 1 176 * 177 * phys block 65: 178 * tee_fs_htree_node_image 62 vers 0 @ offs = 0 179 * tee_fs_htree_node_image 62 vers 1 @ offs = node_size 180 * tee_fs_htree_node_image 63 vers 0 @ offs = node_size * 2 181 * tee_fs_htree_node_image 63 vers 1 @ offs = node_size * 3 182 * ... 183 * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122 184 * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123 185 * 186 * ... 187 */ 188 189 switch (type) { 190 case TEE_FS_HTREE_TYPE_HEAD: 191 *offs = sizeof(struct tee_fs_htree_image) * vers; 192 *size = sizeof(struct tee_fs_htree_image); 193 return TEE_SUCCESS; 194 case TEE_FS_HTREE_TYPE_NODE: 195 pbn = 1 + ((idx / block_nodes) * block_nodes * 2); 196 *offs = pbn * BLOCK_SIZE + 197 2 * node_size * (idx % block_nodes) + 198 node_size * vers; 199 *size = node_size; 200 return TEE_SUCCESS; 201 case TEE_FS_HTREE_TYPE_BLOCK: 202 bidx = 2 * idx + vers; 203 pbn = 2 + bidx + bidx / (block_nodes * 2 - 1); 204 *offs = pbn * BLOCK_SIZE; 205 *size = BLOCK_SIZE; 206 return TEE_SUCCESS; 207 default: 208 return TEE_ERROR_GENERIC; 209 } 210 } 211 212 static TEE_Result ree_fs_rpc_read_init(void *aux, 213 struct tee_fs_rpc_operation *op, 214 enum tee_fs_htree_type type, size_t idx, 215 uint8_t vers, void **data) 216 { 217 struct tee_fs_fd *fdp = aux; 218 TEE_Result res; 219 size_t offs; 220 size_t size; 221 222 res = get_offs_size(type, idx, vers, &offs, &size); 223 if (res != TEE_SUCCESS) 224 return res; 225 226 return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 227 offs, size, data); 228 } 229 230 static TEE_Result ree_fs_rpc_write_init(void *aux, 231 struct tee_fs_rpc_operation *op, 232 enum tee_fs_htree_type type, size_t idx, 233 uint8_t vers, void **data) 234 { 235 struct tee_fs_fd *fdp = aux; 236 TEE_Result res; 237 size_t offs; 238 size_t size; 239 240 res = get_offs_size(type, idx, vers, &offs, &size); 241 if (res != TEE_SUCCESS) 242 return res; 243 244 return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 245 offs, size, data); 246 } 247 248 static const struct tee_fs_htree_storage ree_fs_storage_ops = { 249 .block_size = BLOCK_SIZE, 250 .rpc_read_init = ree_fs_rpc_read_init, 251 .rpc_write_init = ree_fs_rpc_write_init, 252 }; 253 254 static TEE_Result open_internal(const char *file, bool create, 255 struct tee_file_handle **fh) 256 { 257 TEE_Result res; 258 size_t len; 259 struct tee_fs_fd *fdp = NULL; 260 261 if (!file) 262 return TEE_ERROR_BAD_PARAMETERS; 263 264 len = strlen(file) + 1; 265 if (len > TEE_FS_NAME_MAX) 266 return TEE_ERROR_BAD_PARAMETERS; 267 268 fdp = calloc(1, sizeof(struct tee_fs_fd)); 269 if (!fdp) 270 return TEE_ERROR_OUT_OF_MEMORY; 271 fdp->fd = -1; 272 273 mutex_lock(&ree_fs_mutex); 274 275 if (create) 276 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, file, &fdp->fd); 277 else 278 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, file, &fdp->fd); 279 280 if (res != TEE_SUCCESS) 281 goto out; 282 283 res = tee_fs_htree_open(create, &ree_fs_storage_ops, fdp, &fdp->ht); 284 out: 285 if (res == TEE_SUCCESS) { 286 *fh = (struct tee_file_handle *)fdp; 287 } else { 288 if (fdp->fd != -1) 289 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 290 if (create) 291 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file); 292 free(fdp); 293 } 294 295 mutex_unlock(&ree_fs_mutex); 296 return res; 297 } 298 299 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh) 300 { 301 return open_internal(file, false, fh); 302 } 303 304 static TEE_Result ree_fs_create(const char *file, struct tee_file_handle **fh) 305 { 306 return open_internal(file, true, fh); 307 } 308 309 static void ree_fs_close(struct tee_file_handle **fh) 310 { 311 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 312 313 if (fdp) { 314 tee_fs_htree_close(&fdp->ht); 315 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 316 free(fdp); 317 *fh = NULL; 318 } 319 } 320 321 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, 322 tee_fs_off_t new_file_len) 323 { 324 TEE_Result res; 325 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 326 327 if ((size_t)new_file_len > meta->length) { 328 size_t ext_len = new_file_len - meta->length; 329 330 res = out_of_place_write(fdp, meta->length, NULL, ext_len); 331 if (res != TEE_SUCCESS) 332 return res; 333 } else { 334 size_t offs; 335 size_t sz; 336 337 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, 338 ROUNDUP(new_file_len, BLOCK_SIZE) / 339 BLOCK_SIZE, 1, &offs, &sz); 340 if (res != TEE_SUCCESS) 341 return res; 342 343 res = tee_fs_htree_truncate(&fdp->ht, 344 new_file_len / BLOCK_SIZE); 345 if (res != TEE_SUCCESS) 346 return res; 347 348 res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd, 349 offs + sz); 350 if (res != TEE_SUCCESS) 351 return res; 352 353 meta->length = new_file_len; 354 } 355 356 return tee_fs_htree_sync_to_storage(&fdp->ht); 357 } 358 359 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos, 360 void *buf, size_t *len) 361 { 362 TEE_Result res; 363 int start_block_num; 364 int end_block_num; 365 size_t remain_bytes; 366 uint8_t *data_ptr = buf; 367 uint8_t *block = NULL; 368 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 369 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 370 371 mutex_lock(&ree_fs_mutex); 372 373 remain_bytes = *len; 374 if ((pos + remain_bytes) < remain_bytes || pos > meta->length) 375 remain_bytes = 0; 376 else if (pos + remain_bytes > meta->length) 377 remain_bytes = meta->length - pos; 378 379 *len = remain_bytes; 380 381 if (!remain_bytes) { 382 res = TEE_SUCCESS; 383 goto exit; 384 } 385 386 start_block_num = pos_to_block_num(pos); 387 end_block_num = pos_to_block_num(pos + remain_bytes - 1); 388 389 block = malloc(BLOCK_SIZE); 390 if (!block) { 391 res = TEE_ERROR_OUT_OF_MEMORY; 392 goto exit; 393 } 394 395 while (start_block_num <= end_block_num) { 396 size_t offset = pos % BLOCK_SIZE; 397 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); 398 399 if (size_to_read + offset > BLOCK_SIZE) 400 size_to_read = BLOCK_SIZE - offset; 401 402 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block); 403 if (res != TEE_SUCCESS) 404 goto exit; 405 406 memcpy(data_ptr, block + offset, size_to_read); 407 408 data_ptr += size_to_read; 409 remain_bytes -= size_to_read; 410 pos += size_to_read; 411 412 start_block_num++; 413 } 414 res = TEE_SUCCESS; 415 exit: 416 mutex_unlock(&ree_fs_mutex); 417 free(block); 418 return res; 419 } 420 421 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, 422 const void *buf, size_t len) 423 { 424 TEE_Result res; 425 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 426 size_t file_size; 427 428 if (!len) 429 return TEE_SUCCESS; 430 431 mutex_lock(&ree_fs_mutex); 432 433 file_size = tee_fs_htree_get_meta(fdp->ht)->length; 434 435 if ((pos + len) < len) { 436 res = TEE_ERROR_BAD_PARAMETERS; 437 goto exit; 438 } 439 440 if (file_size < pos) { 441 res = ree_fs_ftruncate_internal(fdp, pos); 442 if (res != TEE_SUCCESS) 443 goto exit; 444 } 445 446 res = out_of_place_write(fdp, pos, buf, len); 447 if (res != TEE_SUCCESS) 448 goto exit; 449 450 exit: 451 if (res == TEE_SUCCESS) 452 res = tee_fs_htree_sync_to_storage(&fdp->ht); 453 mutex_unlock(&ree_fs_mutex); 454 return res; 455 } 456 457 static TEE_Result ree_fs_rename(const char *old, const char *new, 458 bool overwrite) 459 { 460 TEE_Result res; 461 462 mutex_lock(&ree_fs_mutex); 463 res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite); 464 mutex_unlock(&ree_fs_mutex); 465 466 return res; 467 } 468 469 static TEE_Result ree_fs_remove(const char *file) 470 { 471 TEE_Result res; 472 473 mutex_lock(&ree_fs_mutex); 474 res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file); 475 mutex_unlock(&ree_fs_mutex); 476 477 return res; 478 } 479 480 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 481 { 482 TEE_Result res; 483 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 484 485 mutex_lock(&ree_fs_mutex); 486 res = ree_fs_ftruncate_internal(fdp, len); 487 mutex_unlock(&ree_fs_mutex); 488 489 return res; 490 } 491 492 const struct tee_file_operations ree_fs_ops = { 493 .open = ree_fs_open, 494 .create = ree_fs_create, 495 .close = ree_fs_close, 496 .read = ree_fs_read, 497 .write = ree_fs_write, 498 .truncate = ree_fs_truncate, 499 .rename = ree_fs_rename, 500 .remove = ree_fs_remove, 501 .opendir = ree_fs_opendir_rpc, 502 .closedir = ree_fs_closedir_rpc, 503 .readdir = ree_fs_readdir_rpc, 504 }; 505