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