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 /* TEE FS operation */ 41 #define TEE_FS_OPEN 1 42 #define TEE_FS_CLOSE 2 43 #define TEE_FS_READ 3 44 #define TEE_FS_WRITE 4 45 #define TEE_FS_SEEK 5 46 #define TEE_FS_UNLINK 6 47 #define TEE_FS_RENAME 7 48 #define TEE_FS_TRUNC 8 49 #define TEE_FS_MKDIR 9 50 #define TEE_FS_OPENDIR 10 51 #define TEE_FS_CLOSEDIR 11 52 #define TEE_FS_READDIR 12 53 #define TEE_FS_RMDIR 13 54 #define TEE_FS_ACCESS 14 55 #define TEE_FS_LINK 15 56 #define TEE_FS_BEGIN 16 /* SQL FS: begin transaction */ 57 #define TEE_FS_END 17 /* SQL FS: end transaction */ 58 59 #define TEE_FS_MODE_NONE 0 60 #define TEE_FS_MODE_IN 1 61 #define TEE_FS_MODE_OUT 2 62 63 struct tee_fs_rpc { 64 int op; 65 int flags; 66 int arg; 67 int fd; 68 uint32_t len; 69 int res; 70 }; 71 72 struct tee_fs_dir { 73 int nw_dir; 74 struct tee_fs_dirent d; 75 }; 76 77 static TEE_Result tee_fs_rpc_send_cmd(int cmd_id, struct tee_fs_rpc *bf_cmd, 78 void *data, uint32_t len, uint32_t mode) 79 { 80 TEE_Result ret; 81 struct optee_msg_param params; 82 paddr_t phpayload = 0; 83 uint64_t cpayload = 0; 84 struct tee_fs_rpc *bf; 85 int res = TEE_ERROR_GENERIC; 86 87 assert(cmd_id == OPTEE_MSG_RPC_CMD_FS || 88 cmd_id == OPTEE_MSG_RPC_CMD_SQL_FS); 89 90 bf = tee_fs_rpc_cache_alloc(sizeof(struct tee_fs_rpc) + len, 91 &phpayload, &cpayload); 92 if (!bf) 93 goto exit; 94 95 memset(¶ms, 0, sizeof(params)); 96 params.attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT; 97 params.u.tmem.buf_ptr = phpayload; 98 params.u.tmem.size = sizeof(struct tee_fs_rpc) + len; 99 params.u.tmem.shm_ref = cpayload; 100 101 /* fill in parameters */ 102 *bf = *bf_cmd; 103 104 if (mode & TEE_FS_MODE_IN) 105 memcpy((void *)(bf + 1), data, len); 106 107 ret = thread_rpc_cmd(cmd_id, 1, ¶ms); 108 /* update result */ 109 *bf_cmd = *bf; 110 if (ret != TEE_SUCCESS) 111 goto exit; 112 113 if (mode & TEE_FS_MODE_OUT) { 114 uint32_t olen = MIN(len, bf->len); 115 116 memcpy(data, (void *)(bf + 1), olen); 117 } 118 119 res = TEE_SUCCESS; 120 121 exit: 122 return res; 123 } 124 125 int tee_fs_rpc_access(int id, const char *name, int mode) 126 { 127 struct tee_fs_rpc head = { 0 }; 128 TEE_Result res; 129 int rc = RPC_FAILED; 130 size_t len; 131 132 DMSG("(id: %d, name: %s, mode: %d)...", id, name, mode); 133 134 if (!name) 135 goto exit; 136 137 len = strlen(name) + 1; 138 if (len <= 1) 139 goto exit; 140 141 head.op = TEE_FS_ACCESS; 142 head.flags = mode; 143 144 res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len, TEE_FS_MODE_IN); 145 if (res != TEE_SUCCESS) 146 goto exit; 147 148 rc = head.res; 149 exit: 150 DMSG("...%d", rc); 151 return rc; 152 } 153 154 int tee_fs_rpc_begin_transaction(int id) 155 { 156 struct tee_fs_rpc head = { 0 }; 157 TEE_Result res; 158 int rc = RPC_FAILED; 159 160 assert(id == OPTEE_MSG_RPC_CMD_SQL_FS); 161 162 DMSG("(id: %d)...", id); 163 164 /* fill in parameters */ 165 head.op = TEE_FS_BEGIN; 166 head.fd = -1; 167 168 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, 169 TEE_FS_MODE_NONE); 170 if (res != TEE_SUCCESS) 171 goto exit; 172 173 rc = head.res; 174 exit: 175 DMSG("...%d", rc); 176 return rc; 177 } 178 179 int tee_fs_rpc_close(int id, int fd) 180 { 181 struct tee_fs_rpc head = { 0 }; 182 TEE_Result res; 183 int rc = RPC_FAILED; 184 185 DMSG("(id: %d, fd: %d)...", id, fd); 186 187 head.op = TEE_FS_CLOSE; 188 head.fd = fd; 189 190 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 191 if (res != TEE_SUCCESS) 192 goto exit; 193 194 rc = head.res; 195 exit: 196 DMSG("...%d", rc); 197 return rc; 198 } 199 200 int tee_fs_rpc_end_transaction(int id, bool rollback) 201 { 202 struct tee_fs_rpc head = { 0 }; 203 TEE_Result res; 204 int rc = RPC_FAILED; 205 206 assert(id == OPTEE_MSG_RPC_CMD_SQL_FS); 207 208 DMSG("(id: %d, rollback: %d)...", id, rollback); 209 210 head.op = TEE_FS_END; 211 head.arg = rollback; 212 head.fd = -1; 213 214 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 215 if (res != TEE_SUCCESS) 216 goto exit; 217 218 rc = head.res; 219 exit: 220 DMSG("...%d", rc); 221 return rc; 222 } 223 224 int tee_fs_rpc_ftruncate(int id, int fd, tee_fs_off_t length) 225 { 226 struct tee_fs_rpc head = { 0 }; 227 TEE_Result res; 228 int rc = RPC_FAILED; 229 230 DMSG("(id: %d, fd: %d, length: %" PRId64 ")...", id, fd, length); 231 232 head.op = TEE_FS_TRUNC; 233 head.fd = fd; 234 head.arg = length; 235 236 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 237 if (res != TEE_SUCCESS) 238 goto exit; 239 240 rc = head.res; 241 exit: 242 DMSG("...%d", rc); 243 return rc; 244 } 245 246 int tee_fs_rpc_link(int id, const char *old, const char *nw) 247 { 248 size_t len_old; 249 size_t len_new; 250 size_t len; 251 struct tee_fs_rpc head = { 0 }; 252 char *tmp = NULL; 253 TEE_Result res; 254 int rc = RPC_FAILED; 255 256 DMSG("(id: %d, old: %s, nw: %s)...", id, old, nw); 257 258 if (!old || !nw) 259 goto exit; 260 261 len_old = strlen(old) + 1; 262 len_new = strlen(nw) + 1; 263 len = len_old + len_new; 264 265 tmp = malloc(len); 266 if (!tmp) 267 goto exit; 268 memcpy(tmp, old, len_old); 269 memcpy(tmp + len_old, nw, len_new); 270 271 head.op = TEE_FS_LINK; 272 273 res = tee_fs_rpc_send_cmd(id, &head, tmp, len, TEE_FS_MODE_IN); 274 if (res != TEE_SUCCESS) 275 goto exit; 276 277 rc = head.res; 278 exit: 279 free(tmp); 280 DMSG("...%d", rc); 281 return rc; 282 } 283 284 tee_fs_off_t tee_fs_rpc_lseek(int id, int fd, tee_fs_off_t offset, 285 int whence) 286 { 287 struct tee_fs_rpc head = { 0 }; 288 tee_fs_off_t rc = RPC_FAILED; 289 TEE_Result res; 290 291 DMSG("(id: %d, fd: %d, offset: %" PRId64 ", whence: %d)...", id, fd, 292 offset, whence); 293 294 head.op = TEE_FS_SEEK; 295 head.fd = fd; 296 head.arg = offset; 297 head.flags = whence; 298 299 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 300 if (res != TEE_SUCCESS) 301 goto exit; 302 303 rc = head.res; 304 exit: 305 DMSG("...%" PRId64, rc); 306 return rc; 307 } 308 309 int tee_fs_rpc_mkdir(int id, const char *path, tee_fs_mode_t mode) 310 { 311 struct tee_fs_rpc head = { 0 }; 312 TEE_Result res; 313 uint32_t len; 314 int rc = RPC_FAILED; 315 316 DMSG("(id: %d, path: %s, mode: %d)...", id, path, mode); 317 318 if (!path) 319 goto exit; 320 321 len = strlen(path) + 1; 322 if (len <= 1) 323 goto exit; 324 325 head.op = TEE_FS_MKDIR; 326 head.flags = mode; 327 328 res = tee_fs_rpc_send_cmd(id, &head, (void *)path, len, 329 TEE_FS_MODE_IN); 330 if (res != TEE_SUCCESS) 331 goto exit; 332 333 rc = head.res; 334 exit: 335 DMSG("...%d", rc); 336 return rc; 337 } 338 339 int tee_fs_rpc_open(int id, const char *file, int flags) 340 { 341 struct tee_fs_rpc head = { 0 }; 342 TEE_Result res; 343 int rc = RPC_FAILED; 344 size_t len; 345 346 DMSG("(id: %d, file: %s, flags: %d)...", id, file, flags); 347 348 if (!file) 349 goto exit; 350 351 len = strlen(file) + 1; 352 if (len <= 1) 353 goto exit; 354 355 head.op = TEE_FS_OPEN; 356 head.flags = flags; 357 358 res = tee_fs_rpc_send_cmd(id, &head, (void *)file, len, 359 TEE_FS_MODE_IN); 360 if (res != TEE_SUCCESS) 361 goto exit; 362 363 rc = head.res; 364 exit: 365 DMSG("...%d", rc); 366 return rc; 367 } 368 369 struct tee_fs_dir *tee_fs_rpc_opendir(int id, const char *name) 370 { 371 struct tee_fs_rpc head = { 0 }; 372 struct tee_fs_dir *dir = NULL; 373 size_t len; 374 TEE_Result res = TEE_SUCCESS; 375 376 DMSG("(id: %d, name: %s)...", id, name); 377 378 if (!name) 379 goto exit; 380 381 len = strlen(name) + 1; 382 if (len <= 1) 383 goto exit; 384 385 dir = malloc(sizeof(struct tee_fs_dir)); 386 if (!dir) 387 goto exit; 388 389 head.op = TEE_FS_OPENDIR; 390 391 res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len, 392 TEE_FS_MODE_IN); 393 if (res != TEE_SUCCESS) 394 goto free_and_exit; 395 if (head.res < 0) 396 goto free_and_exit; 397 398 dir->nw_dir = head.res; 399 dir->d.d_name = NULL; 400 401 goto exit; 402 403 free_and_exit: 404 free(dir); 405 dir = NULL; 406 exit: 407 DMSG("...%p", (void *)dir); 408 return dir; 409 } 410 411 int tee_fs_rpc_read(int id, int fd, void *buf, size_t len) 412 { 413 struct tee_fs_rpc head = { 0 }; 414 TEE_Result res; 415 int rc = RPC_FAILED; 416 417 DMSG("(id: %d, fd: %d, buf: %p, len: %zu)...", id, fd, (void *)buf, 418 len); 419 420 if (!len) { 421 res = 0; 422 goto exit; 423 } 424 425 if (!buf) 426 goto exit; 427 428 head.op = TEE_FS_READ; 429 head.fd = fd; 430 head.len = (uint32_t)len; 431 432 res = tee_fs_rpc_send_cmd(id, &head, (void *)buf, len, 433 TEE_FS_MODE_OUT); 434 if (res != TEE_SUCCESS) 435 goto exit; 436 437 rc = head.res; 438 exit: 439 DMSG("...%d", rc); 440 return rc; 441 } 442 443 struct tee_fs_dirent *tee_fs_rpc_readdir(int id, struct tee_fs_dir *d) 444 { 445 struct tee_fs_dirent *rc = NULL; 446 char fname[TEE_FS_NAME_MAX + 1]; 447 struct tee_fs_rpc head = { 0 }; 448 TEE_Result res; 449 450 DMSG("(id: %d, d: %p)...", id, (void *)d); 451 452 if (!d) 453 goto exit; 454 455 head.op = TEE_FS_READDIR; 456 head.arg = (int)d->nw_dir; 457 head.len = sizeof(fname); 458 459 res = tee_fs_rpc_send_cmd(id, &head, fname, sizeof(fname), 460 TEE_FS_MODE_OUT); 461 if (res != TEE_SUCCESS) 462 goto exit; 463 464 if (head.res < 0) 465 goto exit; 466 467 if (!head.len || head.len > sizeof(fname)) 468 goto exit; 469 470 fname[head.len - 1] = '\0'; /* make sure it's zero terminated */ 471 free(d->d.d_name); 472 d->d.d_name = strdup(fname); 473 if (!d->d.d_name) 474 goto exit; 475 476 rc = &d->d; 477 exit: 478 DMSG("...%p", (void *)rc); 479 return rc; 480 } 481 482 int tee_fs_rpc_rename(int id, const char *old, const char *nw) 483 { 484 size_t len_old; 485 size_t len_new; 486 size_t len; 487 struct tee_fs_rpc head = { 0 }; 488 char *tmp = NULL; 489 TEE_Result res; 490 int rc = RPC_FAILED; 491 492 DMSG("(id: %d, old: %s, nw: %s)...", id, old, nw); 493 494 if (!old || !nw) 495 goto exit; 496 497 len_old = strlen(old) + 1; 498 len_new = strlen(nw) + 1; 499 len = len_old + len_new; 500 501 tmp = malloc(len); 502 if (!tmp) 503 goto exit; 504 505 memcpy(tmp, old, len_old); 506 memcpy(tmp + len_old, nw, len_new); 507 508 head.op = TEE_FS_RENAME; 509 510 res = tee_fs_rpc_send_cmd(id, &head, tmp, len, TEE_FS_MODE_IN); 511 if (res != TEE_SUCCESS) 512 goto exit; 513 514 rc = head.res; 515 exit: 516 free(tmp); 517 DMSG("...%d", rc); 518 return rc; 519 } 520 521 int tee_fs_rpc_write(int id, int fd, const void *buf, size_t len) 522 { 523 struct tee_fs_rpc head = { 0 }; 524 TEE_Result res; 525 int rc = RPC_FAILED; 526 527 DMSG("(id: %d, fd: %d, buf: %p, len: %zu)...", id, fd, buf, len); 528 529 if (!len) { 530 res = 0; 531 goto exit; 532 } 533 534 if (!buf) 535 goto exit; 536 537 head.op = TEE_FS_WRITE; 538 head.fd = fd; 539 head.len = (uint32_t)len; 540 541 res = tee_fs_rpc_send_cmd(id, &head, (void *)buf, len, TEE_FS_MODE_IN); 542 if (res != TEE_SUCCESS) 543 goto exit; 544 545 rc = head.res; 546 exit: 547 DMSG("...%d", rc); 548 return rc; 549 } 550 551 int tee_fs_rpc_closedir(int id, struct tee_fs_dir *d) 552 { 553 struct tee_fs_rpc head = { 0 }; 554 TEE_Result res; 555 int rc = RPC_FAILED; 556 557 DMSG("(id: %d, d: %p)...", id, (void *)d); 558 559 if (!d) { 560 rc = 0; 561 goto exit; 562 } 563 564 head.op = TEE_FS_CLOSEDIR; 565 head.arg = (int)d->nw_dir; 566 567 res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE); 568 if (res != TEE_SUCCESS) 569 goto exit; 570 571 rc = head.res; 572 exit: 573 if (d) 574 free(d->d.d_name); 575 free(d); 576 577 DMSG("...%d", rc); 578 return rc; 579 } 580 581 int tee_fs_rpc_rmdir(int id, const char *name) 582 { 583 struct tee_fs_rpc head = { 0 }; 584 TEE_Result res; 585 int rc = RPC_FAILED; 586 size_t len; 587 588 DMSG("(id: %d, name: %s)...", id, name); 589 590 if (!name) 591 goto exit; 592 593 len = strlen(name) + 1; 594 if (len <= 1) 595 goto exit; 596 597 head.op = TEE_FS_RMDIR; 598 599 res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len, 600 TEE_FS_MODE_IN); 601 if (res != TEE_SUCCESS) 602 goto exit; 603 604 rc = head.res; 605 exit: 606 DMSG("...%d", rc); 607 return rc; 608 } 609 610 int tee_fs_rpc_unlink(int id, const char *file) 611 { 612 struct tee_fs_rpc head = { 0 }; 613 size_t len; 614 TEE_Result res; 615 int rc = RPC_FAILED; 616 617 DMSG("(id: %d, file: %s)...", id, file); 618 619 if (!file) 620 goto exit; 621 622 len = strlen(file) + 1; 623 if (len <= 1) 624 goto exit; 625 626 head.op = TEE_FS_UNLINK; 627 628 res = tee_fs_rpc_send_cmd(id, &head, (void *)file, len, 629 TEE_FS_MODE_IN); 630 if (res != TEE_SUCCESS) 631 goto exit; 632 633 rc = head.res; 634 exit: 635 DMSG("...%d", rc); 636 return rc; 637 } 638