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 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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_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_MRF_OPENDIR, 0, 0), 331 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX), 332 [2] = THREAD_PARAM_VALUE(OUT, 0, 0, 0), 333 } 334 }; 335 336 res = operation_commit(&op); 337 338 if (res != TEE_SUCCESS) 339 goto err_exit; 340 341 dir->nw_dir = op.params[2].u.value.a; 342 *d = dir; 343 344 return TEE_SUCCESS; 345 err_exit: 346 free(dir); 347 348 return res; 349 } 350 351 TEE_Result tee_fs_rpc_closedir(uint32_t id, struct tee_fs_dir *d) 352 { 353 struct tee_fs_rpc_operation op = { 354 .id = id, .num_params = 1, .params = { 355 [0] = THREAD_PARAM_VALUE(IN, OPTEE_MRF_CLOSEDIR, 356 d->nw_dir, 0), 357 } 358 }; 359 360 free(d); 361 return operation_commit(&op); 362 } 363 364 TEE_Result tee_fs_rpc_readdir(uint32_t id, struct tee_fs_dir *d, 365 struct tee_fs_dirent **ent) 366 { 367 TEE_Result res; 368 struct mobj *mobj; 369 void *va; 370 const size_t max_name_len = TEE_FS_NAME_MAX + 1; 371 372 if (!d) 373 return TEE_ERROR_ITEM_NOT_FOUND; 374 375 va = tee_fs_rpc_cache_alloc(max_name_len, &mobj); 376 if (!va) 377 return TEE_ERROR_OUT_OF_MEMORY; 378 379 struct tee_fs_rpc_operation op = { 380 .id = id, .num_params = 2, .params = { 381 [0] = THREAD_PARAM_VALUE(IN, OPTEE_MRF_READDIR, 382 d->nw_dir, 0), 383 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, max_name_len), 384 } 385 }; 386 387 res = operation_commit(&op); 388 if (res != TEE_SUCCESS) 389 return res; 390 391 d->d.oidlen = tee_hs2b(va, d->d.oid, strnlen(va, max_name_len), 392 sizeof(d->d.oid)); 393 if (!d->d.oidlen) 394 return TEE_ERROR_OUT_OF_MEMORY; 395 396 *ent = &d->d; 397 return TEE_SUCCESS; 398 } 399