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_read_final = tee_fs_rpc_read_final, 253 .rpc_write_init = ree_fs_rpc_write_init, 254 .rpc_write_final = tee_fs_rpc_write_final, 255 }; 256 257 static TEE_Result open_internal(struct tee_pobj *po, bool create, 258 struct tee_file_handle **fh) 259 { 260 TEE_Result res; 261 struct tee_fs_fd *fdp = NULL; 262 263 fdp = calloc(1, sizeof(struct tee_fs_fd)); 264 if (!fdp) 265 return TEE_ERROR_OUT_OF_MEMORY; 266 fdp->fd = -1; 267 268 mutex_lock(&ree_fs_mutex); 269 270 if (create) 271 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd); 272 else 273 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd); 274 275 if (res != TEE_SUCCESS) 276 goto out; 277 278 res = tee_fs_htree_open(create, &ree_fs_storage_ops, fdp, &fdp->ht); 279 out: 280 if (res == TEE_SUCCESS) { 281 *fh = (struct tee_file_handle *)fdp; 282 } else { 283 if (fdp->fd != -1) 284 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 285 if (create) 286 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po); 287 free(fdp); 288 } 289 290 mutex_unlock(&ree_fs_mutex); 291 return res; 292 } 293 294 static TEE_Result ree_fs_open(struct tee_pobj *po, struct tee_file_handle **fh) 295 { 296 return open_internal(po, false, fh); 297 } 298 299 static TEE_Result ree_fs_create(struct tee_pobj *po, 300 struct tee_file_handle **fh) 301 { 302 return open_internal(po, true, fh); 303 } 304 305 static void ree_fs_close(struct tee_file_handle **fh) 306 { 307 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; 308 309 if (fdp) { 310 tee_fs_htree_close(&fdp->ht); 311 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); 312 free(fdp); 313 *fh = NULL; 314 } 315 } 316 317 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, 318 tee_fs_off_t new_file_len) 319 { 320 TEE_Result res; 321 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 322 323 if ((size_t)new_file_len > meta->length) { 324 size_t ext_len = new_file_len - meta->length; 325 326 res = out_of_place_write(fdp, meta->length, NULL, ext_len); 327 if (res != TEE_SUCCESS) 328 return res; 329 } else { 330 size_t offs; 331 size_t sz; 332 333 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, 334 ROUNDUP(new_file_len, BLOCK_SIZE) / 335 BLOCK_SIZE, 1, &offs, &sz); 336 if (res != TEE_SUCCESS) 337 return res; 338 339 res = tee_fs_htree_truncate(&fdp->ht, 340 new_file_len / BLOCK_SIZE); 341 if (res != TEE_SUCCESS) 342 return res; 343 344 res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd, 345 offs + sz); 346 if (res != TEE_SUCCESS) 347 return res; 348 349 meta->length = new_file_len; 350 } 351 352 return tee_fs_htree_sync_to_storage(&fdp->ht); 353 } 354 355 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos, 356 void *buf, size_t *len) 357 { 358 TEE_Result res; 359 int start_block_num; 360 int end_block_num; 361 size_t remain_bytes; 362 uint8_t *data_ptr = buf; 363 uint8_t *block = NULL; 364 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 365 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); 366 367 mutex_lock(&ree_fs_mutex); 368 369 remain_bytes = *len; 370 if ((pos + remain_bytes) < remain_bytes || pos > meta->length) 371 remain_bytes = 0; 372 else if (pos + remain_bytes > meta->length) 373 remain_bytes = meta->length - pos; 374 375 *len = remain_bytes; 376 377 if (!remain_bytes) { 378 res = TEE_SUCCESS; 379 goto exit; 380 } 381 382 start_block_num = pos_to_block_num(pos); 383 end_block_num = pos_to_block_num(pos + remain_bytes - 1); 384 385 block = malloc(BLOCK_SIZE); 386 if (!block) { 387 res = TEE_ERROR_OUT_OF_MEMORY; 388 goto exit; 389 } 390 391 while (start_block_num <= end_block_num) { 392 size_t offset = pos % BLOCK_SIZE; 393 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); 394 395 if (size_to_read + offset > BLOCK_SIZE) 396 size_to_read = BLOCK_SIZE - offset; 397 398 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block); 399 if (res != TEE_SUCCESS) 400 goto exit; 401 402 memcpy(data_ptr, block + offset, size_to_read); 403 404 data_ptr += size_to_read; 405 remain_bytes -= size_to_read; 406 pos += size_to_read; 407 408 start_block_num++; 409 } 410 res = TEE_SUCCESS; 411 exit: 412 mutex_unlock(&ree_fs_mutex); 413 free(block); 414 return res; 415 } 416 417 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, 418 const void *buf, size_t len) 419 { 420 TEE_Result res; 421 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 422 size_t file_size; 423 424 if (!len) 425 return TEE_SUCCESS; 426 427 mutex_lock(&ree_fs_mutex); 428 429 file_size = tee_fs_htree_get_meta(fdp->ht)->length; 430 431 if ((pos + len) < len) { 432 res = TEE_ERROR_BAD_PARAMETERS; 433 goto exit; 434 } 435 436 if (file_size < pos) { 437 res = ree_fs_ftruncate_internal(fdp, pos); 438 if (res != TEE_SUCCESS) 439 goto exit; 440 } 441 442 res = out_of_place_write(fdp, pos, buf, len); 443 if (res != TEE_SUCCESS) 444 goto exit; 445 446 exit: 447 if (res == TEE_SUCCESS) 448 res = tee_fs_htree_sync_to_storage(&fdp->ht); 449 mutex_unlock(&ree_fs_mutex); 450 return res; 451 } 452 453 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new, 454 bool overwrite) 455 { 456 TEE_Result res; 457 458 mutex_lock(&ree_fs_mutex); 459 res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite); 460 mutex_unlock(&ree_fs_mutex); 461 462 return res; 463 } 464 465 static TEE_Result ree_fs_remove(struct tee_pobj *po) 466 { 467 TEE_Result res; 468 469 mutex_lock(&ree_fs_mutex); 470 res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po); 471 mutex_unlock(&ree_fs_mutex); 472 473 return res; 474 } 475 476 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len) 477 { 478 TEE_Result res; 479 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; 480 481 mutex_lock(&ree_fs_mutex); 482 res = ree_fs_ftruncate_internal(fdp, len); 483 mutex_unlock(&ree_fs_mutex); 484 485 return res; 486 } 487 488 const struct tee_file_operations ree_fs_ops = { 489 .open = ree_fs_open, 490 .create = ree_fs_create, 491 .close = ree_fs_close, 492 .read = ree_fs_read, 493 .write = ree_fs_write, 494 .truncate = ree_fs_truncate, 495 .rename = ree_fs_rename, 496 .remove = ree_fs_remove, 497 .opendir = ree_fs_opendir_rpc, 498 .closedir = ree_fs_closedir_rpc, 499 .readdir = ree_fs_readdir_rpc, 500 }; 501