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