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