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