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