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