1 /* 2 * Copyright (c) 2016, Linaro Limited 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <assert.h> 29 #include <kernel/thread.h> 30 #include <mm/core_memprot.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <tee/tee_fs.h> 34 #include <tee/tee_fs_rpc.h> 35 #include <trace.h> 36 #include <util.h> 37 38 #define RPC_FAILED -1 39 40 struct tee_fs_dir { 41 int nw_dir; 42 struct tee_fs_dirent d; 43 }; 44 45 static TEE_Result tee_fs_rpc_send_cmd(int cmd_id, struct tee_fs_rpc *bf_cmd, 46 void *data, uint32_t len, uint32_t mode) 47 { 48 TEE_Result ret; 49 struct optee_msg_param params; 50 paddr_t phpayload = 0; 51 uint64_t cpayload = 0; 52 struct tee_fs_rpc *bf; 53 int res = TEE_ERROR_GENERIC; 54 55 assert(cmd_id == OPTEE_MSG_RPC_CMD_FS || 56 cmd_id == OPTEE_MSG_RPC_CMD_SQL_FS); 57 58 bf = tee_fs_rpc_cache_alloc(sizeof(struct tee_fs_rpc) + len, 59 &phpayload, &cpayload); 60 if (!bf) 61 goto exit; 62 63 memset(¶ms, 0, sizeof(params)); 64 params.attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT; 65 params.u.tmem.buf_ptr = phpayload; 66 params.u.tmem.size = sizeof(struct tee_fs_rpc) + len; 67 params.u.tmem.shm_ref = cpayload; 68 69 /* fill in parameters */ 70 *bf = *bf_cmd; 71 72 if (mode & TEE_FS_MODE_IN) 73 memcpy((void *)(bf + 1), data, len); 74 75 ret = thread_rpc_cmd(cmd_id, 1, ¶ms); 76 /* update result */ 77 *bf_cmd = *bf; 78 if (ret != TEE_SUCCESS) 79 goto exit; 80 81 if (mode & TEE_FS_MODE_OUT) { 82 uint32_t olen = MIN(len, bf->len); 83 84 memcpy(data, (void *)(bf + 1), olen); 85 } 86 87 res = TEE_SUCCESS; 88 89 exit: 90 return res; 91 } 92 93 int tee_fs_rpc_access(int id, const char *name, int mode) 94 { 95 struct tee_fs_rpc head = { 0 }; 96 TEE_Result res; 97 int rc = RPC_FAILED; 98 size_t len; 99 100 DMSG("(id: %d, name: %s, mode: %d)...", id, name, mode); 101 102 if (!name) 103 goto exit; 104 105 len = strlen(name) + 1; 106 if (len <= 1) 107 goto exit; 108 109 head.op = TEE_FS_ACCESS; 110 head.flags = mode; 111 112 res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len, TEE_FS_MODE_IN); 113 if (res != TEE_SUCCESS) 114 goto exit; 115 116 rc = head.res; 117 exit: 118 DMSG("...%d", rc); 119 return rc; 120 } 121 122 int tee_fs_rpc_begin_transaction(int id) 123 { 124 struct tee_fs_rpc head = { 0 }; 125 TEE_Result res; 126 int rc = RPC_FAILED; 127 128 assert(id == OPTEE_MSG_RPC_CMD_SQL_FS); 129 130 DMSG("(id: %d)...", id); 131 132 /* fill in parameters */ 133 head.op = TEE_FS_BEGIN; 134 head.fd = -1; 135 136 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, 137 TEE_FS_MODE_NONE); 138 if (res != TEE_SUCCESS) 139 goto exit; 140 141 rc = head.res; 142 exit: 143 DMSG("...%d", rc); 144 return rc; 145 } 146 147 int tee_fs_rpc_close(int id, int fd) 148 { 149 struct tee_fs_rpc head = { 0 }; 150 TEE_Result res; 151 int rc = RPC_FAILED; 152 153 DMSG("(id: %d, fd: %d)...", id, fd); 154 155 head.op = TEE_FS_CLOSE; 156 head.fd = fd; 157 158 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 159 if (res != TEE_SUCCESS) 160 goto exit; 161 162 rc = head.res; 163 exit: 164 DMSG("...%d", rc); 165 return rc; 166 } 167 168 int tee_fs_rpc_end_transaction(int id, bool rollback) 169 { 170 struct tee_fs_rpc head = { 0 }; 171 TEE_Result res; 172 int rc = RPC_FAILED; 173 174 assert(id == OPTEE_MSG_RPC_CMD_SQL_FS); 175 176 DMSG("(id: %d, rollback: %d)...", id, rollback); 177 178 head.op = TEE_FS_END; 179 head.arg = rollback; 180 head.fd = -1; 181 182 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 183 if (res != TEE_SUCCESS) 184 goto exit; 185 186 rc = head.res; 187 exit: 188 DMSG("...%d", rc); 189 return rc; 190 } 191 192 int tee_fs_rpc_ftruncate(int id, int fd, tee_fs_off_t length) 193 { 194 struct tee_fs_rpc head = { 0 }; 195 TEE_Result res; 196 int rc = RPC_FAILED; 197 198 DMSG("(id: %d, fd: %d, length: %" PRId64 ")...", id, fd, length); 199 200 head.op = TEE_FS_TRUNC; 201 head.fd = fd; 202 head.arg = length; 203 204 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 205 if (res != TEE_SUCCESS) 206 goto exit; 207 208 rc = head.res; 209 exit: 210 DMSG("...%d", rc); 211 return rc; 212 } 213 214 int tee_fs_rpc_link(int id, const char *old, const char *nw) 215 { 216 size_t len_old; 217 size_t len_new; 218 size_t len; 219 struct tee_fs_rpc head = { 0 }; 220 char *tmp = NULL; 221 TEE_Result res; 222 int rc = RPC_FAILED; 223 224 DMSG("(id: %d, old: %s, nw: %s)...", id, old, nw); 225 226 if (!old || !nw) 227 goto exit; 228 229 len_old = strlen(old) + 1; 230 len_new = strlen(nw) + 1; 231 len = len_old + len_new; 232 233 tmp = malloc(len); 234 if (!tmp) 235 goto exit; 236 memcpy(tmp, old, len_old); 237 memcpy(tmp + len_old, nw, len_new); 238 239 head.op = TEE_FS_LINK; 240 241 res = tee_fs_rpc_send_cmd(id, &head, tmp, len, TEE_FS_MODE_IN); 242 if (res != TEE_SUCCESS) 243 goto exit; 244 245 rc = head.res; 246 exit: 247 free(tmp); 248 DMSG("...%d", rc); 249 return rc; 250 } 251 252 tee_fs_off_t tee_fs_rpc_lseek(int id, int fd, tee_fs_off_t offset, 253 int whence) 254 { 255 struct tee_fs_rpc head = { 0 }; 256 tee_fs_off_t rc = RPC_FAILED; 257 TEE_Result res; 258 259 DMSG("(id: %d, fd: %d, offset: %" PRId64 ", whence: %d)...", id, fd, 260 offset, whence); 261 262 head.op = TEE_FS_SEEK; 263 head.fd = fd; 264 head.arg = offset; 265 head.flags = whence; 266 267 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 268 if (res != TEE_SUCCESS) 269 goto exit; 270 271 rc = head.res; 272 exit: 273 DMSG("...%" PRId64, rc); 274 return rc; 275 } 276 277 int tee_fs_rpc_mkdir(int id, const char *path, tee_fs_mode_t mode) 278 { 279 struct tee_fs_rpc head = { 0 }; 280 TEE_Result res; 281 uint32_t len; 282 int rc = RPC_FAILED; 283 284 DMSG("(id: %d, path: %s, mode: %d)...", id, path, mode); 285 286 if (!path) 287 goto exit; 288 289 len = strlen(path) + 1; 290 if (len <= 1) 291 goto exit; 292 293 head.op = TEE_FS_MKDIR; 294 head.flags = mode; 295 296 res = tee_fs_rpc_send_cmd(id, &head, (void *)path, len, 297 TEE_FS_MODE_IN); 298 if (res != TEE_SUCCESS) 299 goto exit; 300 301 rc = head.res; 302 exit: 303 DMSG("...%d", rc); 304 return rc; 305 } 306 307 int tee_fs_rpc_open(int id, const char *file, int flags) 308 { 309 struct tee_fs_rpc head = { 0 }; 310 TEE_Result res; 311 int rc = RPC_FAILED; 312 size_t len; 313 314 DMSG("(id: %d, file: %s, flags: %d)...", id, file, flags); 315 316 if (!file) 317 goto exit; 318 319 len = strlen(file) + 1; 320 if (len <= 1) 321 goto exit; 322 323 head.op = TEE_FS_OPEN; 324 head.flags = flags; 325 326 res = tee_fs_rpc_send_cmd(id, &head, (void *)file, len, 327 TEE_FS_MODE_IN); 328 if (res != TEE_SUCCESS) 329 goto exit; 330 331 rc = head.res; 332 exit: 333 DMSG("...%d", rc); 334 return rc; 335 } 336 337 struct tee_fs_dir *tee_fs_rpc_opendir(int id, const char *name) 338 { 339 struct tee_fs_rpc head = { 0 }; 340 struct tee_fs_dir *dir = NULL; 341 size_t len; 342 TEE_Result res = TEE_SUCCESS; 343 344 DMSG("(id: %d, name: %s)...", id, name); 345 346 if (!name) 347 goto exit; 348 349 len = strlen(name) + 1; 350 if (len <= 1) 351 goto exit; 352 353 dir = malloc(sizeof(struct tee_fs_dir)); 354 if (!dir) 355 goto exit; 356 357 head.op = TEE_FS_OPENDIR; 358 359 res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len, 360 TEE_FS_MODE_IN); 361 if (res != TEE_SUCCESS) 362 goto free_and_exit; 363 if (head.res < 0) 364 goto free_and_exit; 365 366 dir->nw_dir = head.res; 367 dir->d.d_name = NULL; 368 369 goto exit; 370 371 free_and_exit: 372 free(dir); 373 dir = NULL; 374 exit: 375 DMSG("...%p", (void *)dir); 376 return dir; 377 } 378 379 int tee_fs_rpc_read(int id, int fd, void *buf, size_t len) 380 { 381 struct tee_fs_rpc head = { 0 }; 382 TEE_Result res; 383 int rc = RPC_FAILED; 384 385 DMSG("(id: %d, fd: %d, buf: %p, len: %zu)...", id, fd, (void *)buf, 386 len); 387 388 if (!len) { 389 res = 0; 390 goto exit; 391 } 392 393 if (!buf) 394 goto exit; 395 396 head.op = TEE_FS_READ; 397 head.fd = fd; 398 head.len = (uint32_t)len; 399 400 res = tee_fs_rpc_send_cmd(id, &head, (void *)buf, len, 401 TEE_FS_MODE_OUT); 402 if (res != TEE_SUCCESS) 403 goto exit; 404 405 rc = head.res; 406 exit: 407 DMSG("...%d", rc); 408 return rc; 409 } 410 411 struct tee_fs_dirent *tee_fs_rpc_readdir(int id, struct tee_fs_dir *d) 412 { 413 struct tee_fs_dirent *rc = NULL; 414 char fname[TEE_FS_NAME_MAX + 1]; 415 struct tee_fs_rpc head = { 0 }; 416 TEE_Result res; 417 418 DMSG("(id: %d, d: %p)...", id, (void *)d); 419 420 if (!d) 421 goto exit; 422 423 head.op = TEE_FS_READDIR; 424 head.arg = (int)d->nw_dir; 425 head.len = sizeof(fname); 426 427 res = tee_fs_rpc_send_cmd(id, &head, fname, sizeof(fname), 428 TEE_FS_MODE_OUT); 429 if (res != TEE_SUCCESS) 430 goto exit; 431 432 if (head.res < 0) 433 goto exit; 434 435 if (!head.len || head.len > sizeof(fname)) 436 goto exit; 437 438 fname[head.len - 1] = '\0'; /* make sure it's zero terminated */ 439 free(d->d.d_name); 440 d->d.d_name = strdup(fname); 441 if (!d->d.d_name) 442 goto exit; 443 444 rc = &d->d; 445 exit: 446 DMSG("...%p", (void *)rc); 447 return rc; 448 } 449 450 int tee_fs_rpc_rename(int id, const char *old, const char *nw) 451 { 452 size_t len_old; 453 size_t len_new; 454 size_t len; 455 struct tee_fs_rpc head = { 0 }; 456 char *tmp = NULL; 457 TEE_Result res; 458 int rc = RPC_FAILED; 459 460 DMSG("(id: %d, old: %s, nw: %s)...", id, old, nw); 461 462 if (!old || !nw) 463 goto exit; 464 465 len_old = strlen(old) + 1; 466 len_new = strlen(nw) + 1; 467 len = len_old + len_new; 468 469 tmp = malloc(len); 470 if (!tmp) 471 goto exit; 472 473 memcpy(tmp, old, len_old); 474 memcpy(tmp + len_old, nw, len_new); 475 476 head.op = TEE_FS_RENAME; 477 478 res = tee_fs_rpc_send_cmd(id, &head, tmp, len, TEE_FS_MODE_IN); 479 if (res != TEE_SUCCESS) 480 goto exit; 481 482 rc = head.res; 483 exit: 484 free(tmp); 485 DMSG("...%d", rc); 486 return rc; 487 } 488 489 int tee_fs_rpc_write(int id, int fd, const void *buf, size_t len) 490 { 491 struct tee_fs_rpc head = { 0 }; 492 TEE_Result res; 493 int rc = RPC_FAILED; 494 495 DMSG("(id: %d, fd: %d, buf: %p, len: %zu)...", id, fd, buf, len); 496 497 if (!len) { 498 res = 0; 499 goto exit; 500 } 501 502 if (!buf) 503 goto exit; 504 505 head.op = TEE_FS_WRITE; 506 head.fd = fd; 507 head.len = (uint32_t)len; 508 509 res = tee_fs_rpc_send_cmd(id, &head, (void *)buf, len, TEE_FS_MODE_IN); 510 if (res != TEE_SUCCESS) 511 goto exit; 512 513 rc = head.res; 514 exit: 515 DMSG("...%d", rc); 516 return rc; 517 } 518 519 int tee_fs_rpc_closedir(int id, struct tee_fs_dir *d) 520 { 521 struct tee_fs_rpc head = { 0 }; 522 TEE_Result res; 523 int rc = RPC_FAILED; 524 525 DMSG("(id: %d, d: %p)...", id, (void *)d); 526 527 if (!d) { 528 rc = 0; 529 goto exit; 530 } 531 532 head.op = TEE_FS_CLOSEDIR; 533 head.arg = (int)d->nw_dir; 534 535 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 536 if (res != TEE_SUCCESS) 537 goto exit; 538 539 rc = head.res; 540 exit: 541 if (d) 542 free(d->d.d_name); 543 free(d); 544 545 DMSG("...%d", rc); 546 return rc; 547 } 548 549 int tee_fs_rpc_rmdir(int id, const char *name) 550 { 551 struct tee_fs_rpc head = { 0 }; 552 TEE_Result res; 553 int rc = RPC_FAILED; 554 size_t len; 555 556 DMSG("(id: %d, name: %s)...", id, name); 557 558 if (!name) 559 goto exit; 560 561 len = strlen(name) + 1; 562 if (len <= 1) 563 goto exit; 564 565 head.op = TEE_FS_RMDIR; 566 567 res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len, 568 TEE_FS_MODE_IN); 569 if (res != TEE_SUCCESS) 570 goto exit; 571 572 rc = head.res; 573 exit: 574 DMSG("...%d", rc); 575 return rc; 576 } 577 578 int tee_fs_rpc_unlink(int id, const char *file) 579 { 580 struct tee_fs_rpc head = { 0 }; 581 size_t len; 582 TEE_Result res; 583 int rc = RPC_FAILED; 584 585 DMSG("(id: %d, file: %s)...", id, file); 586 587 if (!file) 588 goto exit; 589 590 len = strlen(file) + 1; 591 if (len <= 1) 592 goto exit; 593 594 head.op = TEE_FS_UNLINK; 595 596 res = tee_fs_rpc_send_cmd(id, &head, (void *)file, len, 597 TEE_FS_MODE_IN); 598 if (res != TEE_SUCCESS) 599 goto exit; 600 601 rc = head.res; 602 exit: 603 DMSG("...%d", rc); 604 return rc; 605 } 606