1 /* 2 * Copyright (c) 2016, 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/tee_misc.h> 30 #include <kernel/thread.h> 31 #include <mm/core_memprot.h> 32 #include <optee_msg_supplicant.h> 33 #include <stdlib.h> 34 #include <string_ext.h> 35 #include <string.h> 36 #include <tee/tee_fs.h> 37 #include <tee/tee_fs_rpc.h> 38 #include <tee/tee_pobj.h> 39 #include <tee/tee_svc_storage.h> 40 #include <trace.h> 41 #include <util.h> 42 43 struct tee_fs_dir { 44 int nw_dir; 45 struct tee_fs_dirent d; 46 }; 47 48 static TEE_Result operation_commit(struct tee_fs_rpc_operation *op) 49 { 50 return thread_rpc_cmd(op->id, op->num_params, op->params); 51 } 52 53 static TEE_Result operation_open(uint32_t id, unsigned int cmd, 54 struct tee_pobj *po, int *fd) 55 { 56 struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 }; 57 TEE_Result res; 58 void *va; 59 paddr_t pa; 60 uint64_t cookie; 61 62 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie); 63 if (!va) 64 return TEE_ERROR_OUT_OF_MEMORY; 65 66 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 67 op.params[0].u.value.a = cmd; 68 69 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 70 op.params[1].u.tmem.buf_ptr = pa; 71 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 72 op.params[1].u.tmem.shm_ref = cookie; 73 res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX, 74 po, po->temporary); 75 if (res != TEE_SUCCESS) 76 return res; 77 78 op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT; 79 80 res = operation_commit(&op); 81 if (res == TEE_SUCCESS) 82 *fd = op.params[2].u.value.a; 83 84 return res; 85 } 86 87 TEE_Result tee_fs_rpc_open(uint32_t id, struct tee_pobj *po, int *fd) 88 { 89 return operation_open(id, OPTEE_MRF_OPEN, po, fd); 90 } 91 92 TEE_Result tee_fs_rpc_create(uint32_t id, struct tee_pobj *po, int *fd) 93 { 94 return operation_open(id, OPTEE_MRF_CREATE, po, fd); 95 } 96 97 static TEE_Result operation_open_dfh(uint32_t id, unsigned int cmd, 98 const struct tee_fs_dirfile_fileh *dfh, 99 int *fd) 100 { 101 struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 }; 102 TEE_Result res; 103 void *va; 104 paddr_t pa; 105 uint64_t cookie; 106 107 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie); 108 if (!va) 109 return TEE_ERROR_OUT_OF_MEMORY; 110 111 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 112 op.params[0].u.value.a = cmd; 113 114 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 115 op.params[1].u.tmem.buf_ptr = pa; 116 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 117 op.params[1].u.tmem.shm_ref = cookie; 118 res = tee_svc_storage_create_filename_dfh(va, TEE_FS_NAME_MAX, dfh); 119 if (res != TEE_SUCCESS) 120 return res; 121 122 op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT; 123 124 res = operation_commit(&op); 125 if (res == TEE_SUCCESS) 126 *fd = op.params[2].u.value.a; 127 128 return res; 129 } 130 131 132 133 TEE_Result tee_fs_rpc_open_dfh(uint32_t id, 134 const struct tee_fs_dirfile_fileh *dfh, int *fd) 135 { 136 return operation_open_dfh(id, OPTEE_MRF_OPEN, dfh, fd); 137 } 138 139 TEE_Result tee_fs_rpc_create_dfh(uint32_t id, 140 const struct tee_fs_dirfile_fileh *dfh, 141 int *fd) 142 { 143 return operation_open_dfh(id, OPTEE_MRF_CREATE, dfh, fd); 144 } 145 146 TEE_Result tee_fs_rpc_close(uint32_t id, int fd) 147 { 148 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 149 150 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 151 op.params[0].u.value.a = OPTEE_MRF_CLOSE; 152 op.params[0].u.value.b = fd; 153 154 return operation_commit(&op); 155 } 156 157 TEE_Result tee_fs_rpc_read_init(struct tee_fs_rpc_operation *op, 158 uint32_t id, int fd, tee_fs_off_t offset, 159 size_t data_len, void **out_data) 160 { 161 uint8_t *va; 162 paddr_t pa; 163 uint64_t cookie; 164 165 if (offset < 0) 166 return TEE_ERROR_BAD_PARAMETERS; 167 168 va = tee_fs_rpc_cache_alloc(data_len, &pa, &cookie); 169 if (!va) 170 return TEE_ERROR_OUT_OF_MEMORY; 171 172 memset(op, 0, sizeof(*op)); 173 op->id = id; 174 op->num_params = 2; 175 176 op->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 177 op->params[0].u.value.a = OPTEE_MRF_READ; 178 op->params[0].u.value.b = fd; 179 op->params[0].u.value.c = offset; 180 181 op->params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; 182 op->params[1].u.tmem.buf_ptr = pa; 183 op->params[1].u.tmem.size = data_len; 184 op->params[1].u.tmem.shm_ref = cookie; 185 186 *out_data = va; 187 188 return TEE_SUCCESS; 189 } 190 191 TEE_Result tee_fs_rpc_read_final(struct tee_fs_rpc_operation *op, 192 size_t *data_len) 193 { 194 TEE_Result res = operation_commit(op); 195 196 if (res == TEE_SUCCESS) 197 *data_len = op->params[1].u.tmem.size; 198 return res; 199 } 200 201 TEE_Result tee_fs_rpc_write_init(struct tee_fs_rpc_operation *op, 202 uint32_t id, int fd, tee_fs_off_t offset, 203 size_t data_len, void **data) 204 { 205 uint8_t *va; 206 paddr_t pa; 207 uint64_t cookie; 208 209 if (offset < 0) 210 return TEE_ERROR_BAD_PARAMETERS; 211 212 va = tee_fs_rpc_cache_alloc(data_len, &pa, &cookie); 213 if (!va) 214 return TEE_ERROR_OUT_OF_MEMORY; 215 216 memset(op, 0, sizeof(*op)); 217 op->id = id; 218 op->num_params = 2; 219 220 221 op->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 222 op->params[0].u.value.a = OPTEE_MRF_WRITE; 223 op->params[0].u.value.b = fd; 224 op->params[0].u.value.c = offset; 225 226 op->params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 227 op->params[1].u.tmem.buf_ptr = pa; 228 op->params[1].u.tmem.size = data_len; 229 op->params[1].u.tmem.shm_ref = cookie; 230 231 *data = va; 232 233 return TEE_SUCCESS; 234 } 235 236 TEE_Result tee_fs_rpc_write_final(struct tee_fs_rpc_operation *op) 237 { 238 return operation_commit(op); 239 } 240 241 TEE_Result tee_fs_rpc_truncate(uint32_t id, int fd, size_t len) 242 { 243 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 244 245 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 246 op.params[0].u.value.a = OPTEE_MRF_TRUNCATE; 247 op.params[0].u.value.b = fd; 248 op.params[0].u.value.c = len; 249 250 return operation_commit(&op); 251 } 252 253 TEE_Result tee_fs_rpc_remove(uint32_t id, struct tee_pobj *po) 254 { 255 TEE_Result res; 256 struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 }; 257 void *va; 258 paddr_t pa; 259 uint64_t cookie; 260 261 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie); 262 if (!va) 263 return TEE_ERROR_OUT_OF_MEMORY; 264 265 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 266 op.params[0].u.value.a = OPTEE_MRF_REMOVE; 267 268 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 269 op.params[1].u.tmem.buf_ptr = pa; 270 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 271 op.params[1].u.tmem.shm_ref = cookie; 272 res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX, 273 po, po->temporary); 274 if (res != TEE_SUCCESS) 275 return res; 276 277 return operation_commit(&op); 278 } 279 280 TEE_Result tee_fs_rpc_remove_dfh(uint32_t id, 281 const struct tee_fs_dirfile_fileh *dfh) 282 { 283 TEE_Result res; 284 struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 }; 285 void *va; 286 paddr_t pa; 287 uint64_t cookie; 288 289 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie); 290 if (!va) 291 return TEE_ERROR_OUT_OF_MEMORY; 292 293 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 294 op.params[0].u.value.a = OPTEE_MRF_REMOVE; 295 296 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 297 op.params[1].u.tmem.buf_ptr = pa; 298 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 299 op.params[1].u.tmem.shm_ref = cookie; 300 res = tee_svc_storage_create_filename_dfh(va, TEE_FS_NAME_MAX, dfh); 301 if (res != TEE_SUCCESS) 302 return res; 303 304 return operation_commit(&op); 305 } 306 307 TEE_Result tee_fs_rpc_rename(uint32_t id, struct tee_pobj *old, 308 struct tee_pobj *new, bool overwrite) 309 { 310 TEE_Result res; 311 struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 }; 312 char *va; 313 paddr_t pa; 314 uint64_t cookie; 315 bool temp; 316 317 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX * 2, &pa, &cookie); 318 if (!va) 319 return TEE_ERROR_OUT_OF_MEMORY; 320 321 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 322 op.params[0].u.value.a = OPTEE_MRF_RENAME; 323 op.params[0].u.value.b = overwrite; 324 325 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 326 op.params[1].u.tmem.buf_ptr = pa; 327 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 328 op.params[1].u.tmem.shm_ref = cookie; 329 if (new) 330 temp = old->temporary; 331 else 332 temp = true; 333 res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX, 334 old, temp); 335 if (res != TEE_SUCCESS) 336 return res; 337 338 op.params[2].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 339 op.params[2].u.tmem.buf_ptr = pa + TEE_FS_NAME_MAX; 340 op.params[2].u.tmem.size = TEE_FS_NAME_MAX; 341 op.params[2].u.tmem.shm_ref = cookie; 342 if (new) { 343 res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX, 344 TEE_FS_NAME_MAX, 345 new, new->temporary); 346 } else { 347 res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX, 348 TEE_FS_NAME_MAX, 349 old, false); 350 } 351 if (res != TEE_SUCCESS) 352 return res; 353 354 return operation_commit(&op); 355 } 356 357 TEE_Result tee_fs_rpc_opendir(uint32_t id, const TEE_UUID *uuid, 358 struct tee_fs_dir **d) 359 { 360 TEE_Result res; 361 struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 }; 362 void *va; 363 paddr_t pa; 364 uint64_t cookie; 365 struct tee_fs_dir *dir = calloc(1, sizeof(*dir)); 366 367 if (!dir) 368 return TEE_ERROR_OUT_OF_MEMORY; 369 370 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie); 371 if (!va) { 372 res = TEE_ERROR_OUT_OF_MEMORY; 373 goto err_exit; 374 } 375 376 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 377 op.params[0].u.value.a = OPTEE_MRF_OPENDIR; 378 379 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 380 op.params[1].u.tmem.buf_ptr = pa; 381 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 382 op.params[1].u.tmem.shm_ref = cookie; 383 res = tee_svc_storage_create_dirname(va, TEE_FS_NAME_MAX, uuid); 384 if (res != TEE_SUCCESS) 385 return res; 386 387 op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT; 388 389 res = operation_commit(&op); 390 391 if (res != TEE_SUCCESS) 392 goto err_exit; 393 394 dir->nw_dir = op.params[2].u.value.a; 395 *d = dir; 396 397 return TEE_SUCCESS; 398 err_exit: 399 free(dir); 400 401 return res; 402 } 403 404 TEE_Result tee_fs_rpc_closedir(uint32_t id, struct tee_fs_dir *d) 405 { 406 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 407 408 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 409 op.params[0].u.value.a = OPTEE_MRF_CLOSEDIR; 410 op.params[0].u.value.b = d->nw_dir; 411 412 free(d); 413 return operation_commit(&op); 414 } 415 416 TEE_Result tee_fs_rpc_readdir(uint32_t id, struct tee_fs_dir *d, 417 struct tee_fs_dirent **ent) 418 { 419 TEE_Result res; 420 struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 }; 421 void *va; 422 paddr_t pa; 423 uint64_t cookie; 424 const size_t max_name_len = TEE_FS_NAME_MAX + 1; 425 426 if (!d) 427 return TEE_ERROR_ITEM_NOT_FOUND; 428 429 va = tee_fs_rpc_cache_alloc(max_name_len, &pa, &cookie); 430 if (!va) 431 return TEE_ERROR_OUT_OF_MEMORY; 432 433 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 434 op.params[0].u.value.a = OPTEE_MRF_READDIR; 435 op.params[0].u.value.b = d->nw_dir; 436 437 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; 438 op.params[1].u.tmem.buf_ptr = pa; 439 op.params[1].u.tmem.size = max_name_len; 440 op.params[1].u.tmem.shm_ref = cookie; 441 442 res = operation_commit(&op); 443 if (res != TEE_SUCCESS) 444 return res; 445 446 d->d.oidlen = tee_hs2b(va, d->d.oid, strnlen(va, max_name_len), 447 sizeof(d->d.oid)); 448 if (!d->d.oidlen) 449 return TEE_ERROR_OUT_OF_MEMORY; 450 451 *ent = &d->d; 452 return TEE_SUCCESS; 453 } 454