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 TEE_Result tee_fs_rpc_close(uint32_t id, int fd) 98 { 99 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 100 101 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 102 op.params[0].u.value.a = OPTEE_MRF_CLOSE; 103 op.params[0].u.value.b = fd; 104 105 return operation_commit(&op); 106 } 107 108 TEE_Result tee_fs_rpc_read_init(struct tee_fs_rpc_operation *op, 109 uint32_t id, int fd, tee_fs_off_t offset, 110 size_t data_len, void **out_data) 111 { 112 uint8_t *va; 113 paddr_t pa; 114 uint64_t cookie; 115 116 if (offset < 0) 117 return TEE_ERROR_BAD_PARAMETERS; 118 119 va = tee_fs_rpc_cache_alloc(data_len, &pa, &cookie); 120 if (!va) 121 return TEE_ERROR_OUT_OF_MEMORY; 122 123 memset(op, 0, sizeof(*op)); 124 op->id = id; 125 op->num_params = 2; 126 127 op->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 128 op->params[0].u.value.a = OPTEE_MRF_READ; 129 op->params[0].u.value.b = fd; 130 op->params[0].u.value.c = offset; 131 132 op->params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; 133 op->params[1].u.tmem.buf_ptr = pa; 134 op->params[1].u.tmem.size = data_len; 135 op->params[1].u.tmem.shm_ref = cookie; 136 137 *out_data = va; 138 139 return TEE_SUCCESS; 140 } 141 142 TEE_Result tee_fs_rpc_read_final(struct tee_fs_rpc_operation *op, 143 size_t *data_len) 144 { 145 TEE_Result res = operation_commit(op); 146 147 if (res == TEE_SUCCESS) 148 *data_len = op->params[1].u.tmem.size; 149 return res; 150 } 151 152 TEE_Result tee_fs_rpc_write_init(struct tee_fs_rpc_operation *op, 153 uint32_t id, int fd, tee_fs_off_t offset, 154 size_t data_len, void **data) 155 { 156 uint8_t *va; 157 paddr_t pa; 158 uint64_t cookie; 159 160 if (offset < 0) 161 return TEE_ERROR_BAD_PARAMETERS; 162 163 va = tee_fs_rpc_cache_alloc(data_len, &pa, &cookie); 164 if (!va) 165 return TEE_ERROR_OUT_OF_MEMORY; 166 167 memset(op, 0, sizeof(*op)); 168 op->id = id; 169 op->num_params = 2; 170 171 172 op->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 173 op->params[0].u.value.a = OPTEE_MRF_WRITE; 174 op->params[0].u.value.b = fd; 175 op->params[0].u.value.c = offset; 176 177 op->params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 178 op->params[1].u.tmem.buf_ptr = pa; 179 op->params[1].u.tmem.size = data_len; 180 op->params[1].u.tmem.shm_ref = cookie; 181 182 *data = va; 183 184 return TEE_SUCCESS; 185 } 186 187 TEE_Result tee_fs_rpc_write_final(struct tee_fs_rpc_operation *op) 188 { 189 return operation_commit(op); 190 } 191 192 TEE_Result tee_fs_rpc_truncate(uint32_t id, int fd, size_t len) 193 { 194 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 195 196 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 197 op.params[0].u.value.a = OPTEE_MRF_TRUNCATE; 198 op.params[0].u.value.b = fd; 199 op.params[0].u.value.c = len; 200 201 return operation_commit(&op); 202 } 203 204 TEE_Result tee_fs_rpc_remove(uint32_t id, struct tee_pobj *po) 205 { 206 TEE_Result res; 207 struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 }; 208 void *va; 209 paddr_t pa; 210 uint64_t cookie; 211 212 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie); 213 if (!va) 214 return TEE_ERROR_OUT_OF_MEMORY; 215 216 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 217 op.params[0].u.value.a = OPTEE_MRF_REMOVE; 218 219 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 220 op.params[1].u.tmem.buf_ptr = pa; 221 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 222 op.params[1].u.tmem.shm_ref = cookie; 223 res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX, 224 po, po->temporary); 225 if (res != TEE_SUCCESS) 226 return res; 227 228 return operation_commit(&op); 229 } 230 231 TEE_Result tee_fs_rpc_rename(uint32_t id, struct tee_pobj *old, 232 struct tee_pobj *new, bool overwrite) 233 { 234 TEE_Result res; 235 struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 }; 236 char *va; 237 paddr_t pa; 238 uint64_t cookie; 239 bool temp; 240 241 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX * 2, &pa, &cookie); 242 if (!va) 243 return TEE_ERROR_OUT_OF_MEMORY; 244 245 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 246 op.params[0].u.value.a = OPTEE_MRF_RENAME; 247 op.params[0].u.value.b = overwrite; 248 249 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 250 op.params[1].u.tmem.buf_ptr = pa; 251 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 252 op.params[1].u.tmem.shm_ref = cookie; 253 if (new) 254 temp = old->temporary; 255 else 256 temp = true; 257 res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX, 258 old, temp); 259 if (res != TEE_SUCCESS) 260 return res; 261 262 op.params[2].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 263 op.params[2].u.tmem.buf_ptr = pa + TEE_FS_NAME_MAX; 264 op.params[2].u.tmem.size = TEE_FS_NAME_MAX; 265 op.params[2].u.tmem.shm_ref = cookie; 266 if (new) { 267 res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX, 268 TEE_FS_NAME_MAX, 269 new, new->temporary); 270 } else { 271 res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX, 272 TEE_FS_NAME_MAX, 273 old, false); 274 } 275 if (res != TEE_SUCCESS) 276 return res; 277 278 return operation_commit(&op); 279 } 280 281 TEE_Result tee_fs_rpc_opendir(uint32_t id, const TEE_UUID *uuid, 282 struct tee_fs_dir **d) 283 { 284 TEE_Result res; 285 struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 }; 286 void *va; 287 paddr_t pa; 288 uint64_t cookie; 289 struct tee_fs_dir *dir = calloc(1, sizeof(*dir)); 290 291 if (!dir) 292 return TEE_ERROR_OUT_OF_MEMORY; 293 294 va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie); 295 if (!va) { 296 res = TEE_ERROR_OUT_OF_MEMORY; 297 goto err_exit; 298 } 299 300 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 301 op.params[0].u.value.a = OPTEE_MRF_OPENDIR; 302 303 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 304 op.params[1].u.tmem.buf_ptr = pa; 305 op.params[1].u.tmem.size = TEE_FS_NAME_MAX; 306 op.params[1].u.tmem.shm_ref = cookie; 307 res = tee_svc_storage_create_dirname(va, TEE_FS_NAME_MAX, uuid); 308 if (res != TEE_SUCCESS) 309 return res; 310 311 op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT; 312 313 res = operation_commit(&op); 314 315 if (res != TEE_SUCCESS) 316 goto err_exit; 317 318 dir->nw_dir = op.params[2].u.value.a; 319 *d = dir; 320 321 return TEE_SUCCESS; 322 err_exit: 323 free(dir); 324 325 return res; 326 } 327 328 TEE_Result tee_fs_rpc_closedir(uint32_t id, struct tee_fs_dir *d) 329 { 330 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 331 332 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 333 op.params[0].u.value.a = OPTEE_MRF_CLOSEDIR; 334 op.params[0].u.value.b = d->nw_dir; 335 336 free(d); 337 return operation_commit(&op); 338 } 339 340 TEE_Result tee_fs_rpc_readdir(uint32_t id, struct tee_fs_dir *d, 341 struct tee_fs_dirent **ent) 342 { 343 TEE_Result res; 344 struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 }; 345 void *va; 346 paddr_t pa; 347 uint64_t cookie; 348 const size_t max_name_len = TEE_FS_NAME_MAX + 1; 349 350 if (!d) 351 return TEE_ERROR_ITEM_NOT_FOUND; 352 353 va = tee_fs_rpc_cache_alloc(max_name_len, &pa, &cookie); 354 if (!va) 355 return TEE_ERROR_OUT_OF_MEMORY; 356 357 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 358 op.params[0].u.value.a = OPTEE_MRF_READDIR; 359 op.params[0].u.value.b = d->nw_dir; 360 361 op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; 362 op.params[1].u.tmem.buf_ptr = pa; 363 op.params[1].u.tmem.size = max_name_len; 364 op.params[1].u.tmem.shm_ref = cookie; 365 366 res = operation_commit(&op); 367 if (res != TEE_SUCCESS) 368 return res; 369 370 d->d.oidlen = tee_hs2b(va, d->d.oid, strnlen(va, max_name_len), 371 sizeof(d->d.oid)); 372 if (!d->d.oidlen) 373 return TEE_ERROR_OUT_OF_MEMORY; 374 375 *ent = &d->d; 376 return TEE_SUCCESS; 377 } 378 379 TEE_Result tee_fs_rpc_begin_transaction(uint32_t id) 380 { 381 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 382 383 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 384 op.params[0].u.value.a = OPTEE_MRF_BEGIN_TRANSACTION; 385 386 return operation_commit(&op); 387 } 388 389 TEE_Result tee_fs_rpc_end_transaction(uint32_t id, bool rollback) 390 { 391 struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 }; 392 393 op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 394 op.params[0].u.value.a = OPTEE_MRF_END_TRANSACTION; 395 op.params[0].u.value.b = rollback; 396 397 return operation_commit(&op); 398 } 399