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