1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2007-2009 Google Inc. and Amit Singh 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following disclaimer 15 * in the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Google Inc. nor the names of its 18 * contributors may be used to endorse or promote products derived from 19 * this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Copyright (C) 2005 Csaba Henk. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 #include <sys/cdefs.h> 59 __FBSDID("$FreeBSD$"); 60 61 #include <sys/types.h> 62 #include <sys/module.h> 63 #include <sys/systm.h> 64 #include <sys/errno.h> 65 #include <sys/param.h> 66 #include <sys/kernel.h> 67 #include <sys/conf.h> 68 #include <sys/uio.h> 69 #include <sys/malloc.h> 70 #include <sys/queue.h> 71 #include <sys/lock.h> 72 #include <sys/sx.h> 73 #include <sys/mutex.h> 74 #include <sys/proc.h> 75 #include <sys/mount.h> 76 #include <sys/vnode.h> 77 #include <sys/signalvar.h> 78 #include <sys/syscallsubr.h> 79 #include <sys/sysctl.h> 80 #include <vm/uma.h> 81 82 #include "fuse.h" 83 #include "fuse_node.h" 84 #include "fuse_ipc.h" 85 #include "fuse_internal.h" 86 87 #define FUSE_DEBUG_MODULE IPC 88 #include "fuse_debug.h" 89 90 static struct fuse_ticket *fticket_alloc(struct fuse_data *data); 91 static void fticket_refresh(struct fuse_ticket *ftick); 92 static void fticket_destroy(struct fuse_ticket *ftick); 93 static int fticket_wait_answer(struct fuse_ticket *ftick); 94 static __inline__ int 95 fticket_aw_pull_uio(struct fuse_ticket *ftick, 96 struct uio *uio); 97 98 static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen); 99 static __inline__ void 100 fuse_setup_ihead(struct fuse_in_header *ihead, 101 struct fuse_ticket *ftick, 102 uint64_t nid, 103 enum fuse_opcode op, 104 size_t blen, 105 pid_t pid, 106 struct ucred *cred); 107 108 static fuse_handler_t fuse_standard_handler; 109 110 SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RW, 0, "FUSE tunables"); 111 SYSCTL_STRING(_vfs_fuse, OID_AUTO, version, CTLFLAG_RD, 112 FUSE_FREEBSD_VERSION, 0, "fuse-freebsd version"); 113 static int fuse_ticket_count = 0; 114 115 SYSCTL_INT(_vfs_fuse, OID_AUTO, ticket_count, CTLFLAG_RW, 116 &fuse_ticket_count, 0, "number of allocated tickets"); 117 static long fuse_iov_permanent_bufsize = 1 << 19; 118 119 SYSCTL_LONG(_vfs_fuse, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW, 120 &fuse_iov_permanent_bufsize, 0, 121 "limit for permanently stored buffer size for fuse_iovs"); 122 static int fuse_iov_credit = 16; 123 124 SYSCTL_INT(_vfs_fuse, OID_AUTO, iov_credit, CTLFLAG_RW, 125 &fuse_iov_credit, 0, 126 "how many times is an oversized fuse_iov tolerated"); 127 128 MALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer"); 129 static uma_zone_t ticket_zone; 130 131 static void 132 fuse_block_sigs(sigset_t *oldset) 133 { 134 sigset_t newset; 135 136 SIGFILLSET(newset); 137 SIGDELSET(newset, SIGKILL); 138 if (kern_sigprocmask(curthread, SIG_BLOCK, &newset, oldset, 0)) 139 panic("%s: Invalid operation for kern_sigprocmask()", 140 __func__); 141 } 142 143 static void 144 fuse_restore_sigs(sigset_t *oldset) 145 { 146 147 if (kern_sigprocmask(curthread, SIG_SETMASK, oldset, NULL, 0)) 148 panic("%s: Invalid operation for kern_sigprocmask()", 149 __func__); 150 } 151 152 void 153 fiov_init(struct fuse_iov *fiov, size_t size) 154 { 155 uint32_t msize = FU_AT_LEAST(size); 156 157 debug_printf("fiov=%p, size=%zd\n", fiov, size); 158 159 fiov->len = 0; 160 161 fiov->base = malloc(msize, M_FUSEMSG, M_WAITOK | M_ZERO); 162 163 fiov->allocated_size = msize; 164 fiov->credit = fuse_iov_credit; 165 } 166 167 void 168 fiov_teardown(struct fuse_iov *fiov) 169 { 170 debug_printf("fiov=%p\n", fiov); 171 172 MPASS(fiov->base != NULL); 173 free(fiov->base, M_FUSEMSG); 174 } 175 176 void 177 fiov_adjust(struct fuse_iov *fiov, size_t size) 178 { 179 debug_printf("fiov=%p, size=%zd\n", fiov, size); 180 181 if (fiov->allocated_size < size || 182 (fuse_iov_permanent_bufsize >= 0 && 183 fiov->allocated_size - size > fuse_iov_permanent_bufsize && 184 --fiov->credit < 0)) { 185 186 fiov->base = realloc(fiov->base, FU_AT_LEAST(size), M_FUSEMSG, 187 M_WAITOK | M_ZERO); 188 if (!fiov->base) { 189 panic("FUSE: realloc failed"); 190 } 191 fiov->allocated_size = FU_AT_LEAST(size); 192 fiov->credit = fuse_iov_credit; 193 } 194 fiov->len = size; 195 } 196 197 void 198 fiov_refresh(struct fuse_iov *fiov) 199 { 200 debug_printf("fiov=%p\n", fiov); 201 202 bzero(fiov->base, fiov->len); 203 fiov_adjust(fiov, 0); 204 } 205 206 static int 207 fticket_ctor(void *mem, int size, void *arg, int flags) 208 { 209 struct fuse_ticket *ftick = mem; 210 struct fuse_data *data = arg; 211 212 debug_printf("ftick=%p data=%p\n", ftick, data); 213 214 FUSE_ASSERT_MS_DONE(ftick); 215 FUSE_ASSERT_AW_DONE(ftick); 216 217 ftick->tk_data = data; 218 219 if (ftick->tk_unique != 0) 220 fticket_refresh(ftick); 221 222 /* May be truncated to 32 bits */ 223 ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1); 224 if (ftick->tk_unique == 0) 225 ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1); 226 227 refcount_init(&ftick->tk_refcount, 1); 228 atomic_add_acq_int(&fuse_ticket_count, 1); 229 230 return 0; 231 } 232 233 static void 234 fticket_dtor(void *mem, int size, void *arg) 235 { 236 struct fuse_ticket *ftick = mem; 237 238 debug_printf("ftick=%p\n", ftick); 239 240 FUSE_ASSERT_MS_DONE(ftick); 241 FUSE_ASSERT_AW_DONE(ftick); 242 243 atomic_subtract_acq_int(&fuse_ticket_count, 1); 244 } 245 246 static int 247 fticket_init(void *mem, int size, int flags) 248 { 249 struct fuse_ticket *ftick = mem; 250 251 FS_DEBUG("ftick=%p\n", ftick); 252 253 bzero(ftick, sizeof(struct fuse_ticket)); 254 255 fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header)); 256 ftick->tk_ms_type = FT_M_FIOV; 257 258 mtx_init(&ftick->tk_aw_mtx, "fuse answer delivery mutex", NULL, MTX_DEF); 259 fiov_init(&ftick->tk_aw_fiov, 0); 260 ftick->tk_aw_type = FT_A_FIOV; 261 262 return 0; 263 } 264 265 static void 266 fticket_fini(void *mem, int size) 267 { 268 struct fuse_ticket *ftick = mem; 269 270 FS_DEBUG("ftick=%p\n", ftick); 271 272 fiov_teardown(&ftick->tk_ms_fiov); 273 fiov_teardown(&ftick->tk_aw_fiov); 274 mtx_destroy(&ftick->tk_aw_mtx); 275 } 276 277 static __inline struct fuse_ticket * 278 fticket_alloc(struct fuse_data *data) 279 { 280 return uma_zalloc_arg(ticket_zone, data, M_WAITOK); 281 } 282 283 static __inline void 284 fticket_destroy(struct fuse_ticket *ftick) 285 { 286 return uma_zfree(ticket_zone, ftick); 287 } 288 289 static __inline__ 290 void 291 fticket_refresh(struct fuse_ticket *ftick) 292 { 293 debug_printf("ftick=%p\n", ftick); 294 295 FUSE_ASSERT_MS_DONE(ftick); 296 FUSE_ASSERT_AW_DONE(ftick); 297 298 fiov_refresh(&ftick->tk_ms_fiov); 299 ftick->tk_ms_bufdata = NULL; 300 ftick->tk_ms_bufsize = 0; 301 ftick->tk_ms_type = FT_M_FIOV; 302 303 bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header)); 304 305 fiov_refresh(&ftick->tk_aw_fiov); 306 ftick->tk_aw_errno = 0; 307 ftick->tk_aw_bufdata = NULL; 308 ftick->tk_aw_bufsize = 0; 309 ftick->tk_aw_type = FT_A_FIOV; 310 311 ftick->tk_flag = 0; 312 } 313 314 static int 315 fticket_wait_answer(struct fuse_ticket *ftick) 316 { 317 sigset_t tset; 318 int err = 0; 319 struct fuse_data *data; 320 321 debug_printf("ftick=%p\n", ftick); 322 fuse_lck_mtx_lock(ftick->tk_aw_mtx); 323 324 if (fticket_answered(ftick)) { 325 goto out; 326 } 327 data = ftick->tk_data; 328 329 if (fdata_get_dead(data)) { 330 err = ENOTCONN; 331 fticket_set_answered(ftick); 332 goto out; 333 } 334 fuse_block_sigs(&tset); 335 err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans", 336 data->daemon_timeout * hz); 337 fuse_restore_sigs(&tset); 338 if (err == EAGAIN) { /* same as EWOULDBLOCK */ 339 #ifdef XXXIP /* die conditionally */ 340 if (!fdata_get_dead(data)) { 341 fdata_set_dead(data); 342 } 343 #endif 344 err = ETIMEDOUT; 345 fticket_set_answered(ftick); 346 } 347 out: 348 if (!(err || fticket_answered(ftick))) { 349 debug_printf("FUSE: requester was woken up but still no answer"); 350 err = ENXIO; 351 } 352 fuse_lck_mtx_unlock(ftick->tk_aw_mtx); 353 354 return err; 355 } 356 357 static __inline__ 358 int 359 fticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio) 360 { 361 int err = 0; 362 size_t len = uio_resid(uio); 363 364 debug_printf("ftick=%p, uio=%p\n", ftick, uio); 365 366 if (len) { 367 switch (ftick->tk_aw_type) { 368 case FT_A_FIOV: 369 fiov_adjust(fticket_resp(ftick), len); 370 err = uiomove(fticket_resp(ftick)->base, len, uio); 371 if (err) { 372 debug_printf("FUSE: FT_A_FIOV: error is %d" 373 " (%p, %zd, %p)\n", 374 err, fticket_resp(ftick)->base, 375 len, uio); 376 } 377 break; 378 379 case FT_A_BUF: 380 ftick->tk_aw_bufsize = len; 381 err = uiomove(ftick->tk_aw_bufdata, len, uio); 382 if (err) { 383 debug_printf("FUSE: FT_A_BUF: error is %d" 384 " (%p, %zd, %p)\n", 385 err, ftick->tk_aw_bufdata, len, uio); 386 } 387 break; 388 389 default: 390 panic("FUSE: unknown answer type for ticket %p", ftick); 391 } 392 } 393 return err; 394 } 395 396 int 397 fticket_pull(struct fuse_ticket *ftick, struct uio *uio) 398 { 399 int err = 0; 400 401 debug_printf("ftick=%p, uio=%p\n", ftick, uio); 402 403 if (ftick->tk_aw_ohead.error) { 404 return 0; 405 } 406 err = fuse_body_audit(ftick, uio_resid(uio)); 407 if (!err) { 408 err = fticket_aw_pull_uio(ftick, uio); 409 } 410 return err; 411 } 412 413 struct fuse_data * 414 fdata_alloc(struct cdev *fdev, struct ucred *cred) 415 { 416 struct fuse_data *data; 417 418 debug_printf("fdev=%p\n", fdev); 419 420 data = malloc(sizeof(struct fuse_data), M_FUSEMSG, M_WAITOK | M_ZERO); 421 422 data->fdev = fdev; 423 mtx_init(&data->ms_mtx, "fuse message list mutex", NULL, MTX_DEF); 424 STAILQ_INIT(&data->ms_head); 425 mtx_init(&data->aw_mtx, "fuse answer list mutex", NULL, MTX_DEF); 426 TAILQ_INIT(&data->aw_head); 427 data->daemoncred = crhold(cred); 428 data->daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT; 429 sx_init(&data->rename_lock, "fuse rename lock"); 430 data->ref = 1; 431 432 return data; 433 } 434 435 void 436 fdata_trydestroy(struct fuse_data *data) 437 { 438 FS_DEBUG("data=%p data.mp=%p data.fdev=%p data.flags=%04x\n", 439 data, data->mp, data->fdev, data->dataflags); 440 441 FS_DEBUG("destroy: data=%p\n", data); 442 data->ref--; 443 MPASS(data->ref >= 0); 444 if (data->ref != 0) 445 return; 446 447 /* Driving off stage all that stuff thrown at device... */ 448 mtx_destroy(&data->ms_mtx); 449 mtx_destroy(&data->aw_mtx); 450 sx_destroy(&data->rename_lock); 451 452 crfree(data->daemoncred); 453 454 free(data, M_FUSEMSG); 455 } 456 457 void 458 fdata_set_dead(struct fuse_data *data) 459 { 460 debug_printf("data=%p\n", data); 461 462 FUSE_LOCK(); 463 if (fdata_get_dead(data)) { 464 FUSE_UNLOCK(); 465 return; 466 } 467 fuse_lck_mtx_lock(data->ms_mtx); 468 data->dataflags |= FSESS_DEAD; 469 wakeup_one(data); 470 selwakeuppri(&data->ks_rsel, PZERO + 1); 471 wakeup(&data->ticketer); 472 fuse_lck_mtx_unlock(data->ms_mtx); 473 FUSE_UNLOCK(); 474 } 475 476 struct fuse_ticket * 477 fuse_ticket_fetch(struct fuse_data *data) 478 { 479 int err = 0; 480 struct fuse_ticket *ftick; 481 482 debug_printf("data=%p\n", data); 483 484 ftick = fticket_alloc(data); 485 486 if (!(data->dataflags & FSESS_INITED)) { 487 /* Sleep until get answer for INIT messsage */ 488 FUSE_LOCK(); 489 if (!(data->dataflags & FSESS_INITED) && data->ticketer > 2) { 490 err = msleep(&data->ticketer, &fuse_mtx, PCATCH | PDROP, 491 "fu_ini", 0); 492 if (err) 493 fdata_set_dead(data); 494 } else 495 FUSE_UNLOCK(); 496 } 497 return ftick; 498 } 499 500 int 501 fuse_ticket_drop(struct fuse_ticket *ftick) 502 { 503 int die; 504 505 die = refcount_release(&ftick->tk_refcount); 506 debug_printf("ftick=%p refcount=%d\n", ftick, ftick->tk_refcount); 507 if (die) 508 fticket_destroy(ftick); 509 510 return die; 511 } 512 513 void 514 fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t * handler) 515 { 516 debug_printf("ftick=%p, handler=%p data=%p\n", ftick, ftick->tk_data, 517 handler); 518 519 if (fdata_get_dead(ftick->tk_data)) { 520 return; 521 } 522 ftick->tk_aw_handler = handler; 523 524 fuse_lck_mtx_lock(ftick->tk_data->aw_mtx); 525 fuse_aw_push(ftick); 526 fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx); 527 } 528 529 void 530 fuse_insert_message(struct fuse_ticket *ftick) 531 { 532 debug_printf("ftick=%p\n", ftick); 533 534 if (ftick->tk_flag & FT_DIRTY) { 535 panic("FUSE: ticket reused without being refreshed"); 536 } 537 ftick->tk_flag |= FT_DIRTY; 538 539 if (fdata_get_dead(ftick->tk_data)) { 540 return; 541 } 542 fuse_lck_mtx_lock(ftick->tk_data->ms_mtx); 543 fuse_ms_push(ftick); 544 wakeup_one(ftick->tk_data); 545 selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1); 546 fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx); 547 } 548 549 static int 550 fuse_body_audit(struct fuse_ticket *ftick, size_t blen) 551 { 552 int err = 0; 553 enum fuse_opcode opcode; 554 555 debug_printf("ftick=%p, blen = %zu\n", ftick, blen); 556 557 opcode = fticket_opcode(ftick); 558 559 switch (opcode) { 560 case FUSE_LOOKUP: 561 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 562 break; 563 564 case FUSE_FORGET: 565 panic("FUSE: a handler has been intalled for FUSE_FORGET"); 566 break; 567 568 case FUSE_GETATTR: 569 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL; 570 break; 571 572 case FUSE_SETATTR: 573 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL; 574 break; 575 576 case FUSE_READLINK: 577 err = (PAGE_SIZE >= blen) ? 0 : EINVAL; 578 break; 579 580 case FUSE_SYMLINK: 581 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 582 break; 583 584 case FUSE_MKNOD: 585 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 586 break; 587 588 case FUSE_MKDIR: 589 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 590 break; 591 592 case FUSE_UNLINK: 593 err = (blen == 0) ? 0 : EINVAL; 594 break; 595 596 case FUSE_RMDIR: 597 err = (blen == 0) ? 0 : EINVAL; 598 break; 599 600 case FUSE_RENAME: 601 err = (blen == 0) ? 0 : EINVAL; 602 break; 603 604 case FUSE_LINK: 605 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 606 break; 607 608 case FUSE_OPEN: 609 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL; 610 break; 611 612 case FUSE_READ: 613 err = (((struct fuse_read_in *)( 614 (char *)ftick->tk_ms_fiov.base + 615 sizeof(struct fuse_in_header) 616 ))->size >= blen) ? 0 : EINVAL; 617 break; 618 619 case FUSE_WRITE: 620 err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL; 621 break; 622 623 case FUSE_STATFS: 624 if (fuse_libabi_geq(ftick->tk_data, 7, 4)) { 625 err = (blen == sizeof(struct fuse_statfs_out)) ? 626 0 : EINVAL; 627 } else { 628 err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL; 629 } 630 break; 631 632 case FUSE_RELEASE: 633 err = (blen == 0) ? 0 : EINVAL; 634 break; 635 636 case FUSE_FSYNC: 637 err = (blen == 0) ? 0 : EINVAL; 638 break; 639 640 case FUSE_SETXATTR: 641 err = (blen == 0) ? 0 : EINVAL; 642 break; 643 644 case FUSE_GETXATTR: 645 case FUSE_LISTXATTR: 646 /* 647 * These can have varying response lengths, and 0 length 648 * isn't necessarily invalid. 649 */ 650 err = 0; 651 break; 652 653 case FUSE_REMOVEXATTR: 654 err = (blen == 0) ? 0 : EINVAL; 655 break; 656 657 case FUSE_FLUSH: 658 err = (blen == 0) ? 0 : EINVAL; 659 break; 660 661 case FUSE_INIT: 662 if (blen == sizeof(struct fuse_init_out) || blen == 8) { 663 err = 0; 664 } else { 665 err = EINVAL; 666 } 667 break; 668 669 case FUSE_OPENDIR: 670 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL; 671 break; 672 673 case FUSE_READDIR: 674 err = (((struct fuse_read_in *)( 675 (char *)ftick->tk_ms_fiov.base + 676 sizeof(struct fuse_in_header) 677 ))->size >= blen) ? 0 : EINVAL; 678 break; 679 680 case FUSE_RELEASEDIR: 681 err = (blen == 0) ? 0 : EINVAL; 682 break; 683 684 case FUSE_FSYNCDIR: 685 err = (blen == 0) ? 0 : EINVAL; 686 break; 687 688 case FUSE_GETLK: 689 panic("FUSE: no response body format check for FUSE_GETLK"); 690 break; 691 692 case FUSE_SETLK: 693 panic("FUSE: no response body format check for FUSE_SETLK"); 694 break; 695 696 case FUSE_SETLKW: 697 panic("FUSE: no response body format check for FUSE_SETLKW"); 698 break; 699 700 case FUSE_ACCESS: 701 err = (blen == 0) ? 0 : EINVAL; 702 break; 703 704 case FUSE_CREATE: 705 err = (blen == sizeof(struct fuse_entry_out) + 706 sizeof(struct fuse_open_out)) ? 0 : EINVAL; 707 break; 708 709 case FUSE_DESTROY: 710 err = (blen == 0) ? 0 : EINVAL; 711 break; 712 713 default: 714 panic("FUSE: opcodes out of sync (%d)\n", opcode); 715 } 716 717 return err; 718 } 719 720 static void 721 fuse_setup_ihead(struct fuse_in_header *ihead, 722 struct fuse_ticket *ftick, 723 uint64_t nid, 724 enum fuse_opcode op, 725 size_t blen, 726 pid_t pid, 727 struct ucred *cred) 728 { 729 ihead->len = sizeof(*ihead) + blen; 730 ihead->unique = ftick->tk_unique; 731 ihead->nodeid = nid; 732 ihead->opcode = op; 733 734 debug_printf("ihead=%p, ftick=%p, nid=%ju, op=%d, blen=%zu\n", 735 ihead, ftick, (uintmax_t)nid, op, blen); 736 737 ihead->pid = pid; 738 ihead->uid = cred->cr_uid; 739 ihead->gid = cred->cr_rgid; 740 } 741 742 /* 743 * fuse_standard_handler just pulls indata and wakes up pretender. 744 * Doesn't try to interpret data, that's left for the pretender. 745 * Though might do a basic size verification before the pull-in takes place 746 */ 747 748 static int 749 fuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio) 750 { 751 int err = 0; 752 753 debug_printf("ftick=%p, uio=%p\n", ftick, uio); 754 755 err = fticket_pull(ftick, uio); 756 757 fuse_lck_mtx_lock(ftick->tk_aw_mtx); 758 759 if (!fticket_answered(ftick)) { 760 fticket_set_answered(ftick); 761 ftick->tk_aw_errno = err; 762 wakeup(ftick); 763 } 764 fuse_lck_mtx_unlock(ftick->tk_aw_mtx); 765 766 return err; 767 } 768 769 void 770 fdisp_make_pid(struct fuse_dispatcher *fdip, 771 enum fuse_opcode op, 772 struct mount *mp, 773 uint64_t nid, 774 pid_t pid, 775 struct ucred *cred) 776 { 777 struct fuse_data *data = fuse_get_mpdata(mp); 778 779 debug_printf("fdip=%p, op=%d, mp=%p, nid=%ju\n", 780 fdip, op, mp, (uintmax_t)nid); 781 782 if (fdip->tick) { 783 fticket_refresh(fdip->tick); 784 } else { 785 fdip->tick = fuse_ticket_fetch(data); 786 } 787 788 FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh, 789 fdip->indata, fdip->iosize); 790 791 fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred); 792 } 793 794 void 795 fdisp_make(struct fuse_dispatcher *fdip, 796 enum fuse_opcode op, 797 struct mount *mp, 798 uint64_t nid, 799 struct thread *td, 800 struct ucred *cred) 801 { 802 RECTIFY_TDCR(td, cred); 803 804 return fdisp_make_pid(fdip, op, mp, nid, td->td_proc->p_pid, cred); 805 } 806 807 void 808 fdisp_make_vp(struct fuse_dispatcher *fdip, 809 enum fuse_opcode op, 810 struct vnode *vp, 811 struct thread *td, 812 struct ucred *cred) 813 { 814 debug_printf("fdip=%p, op=%d, vp=%p\n", fdip, op, vp); 815 RECTIFY_TDCR(td, cred); 816 return fdisp_make_pid(fdip, op, vnode_mount(vp), VTOI(vp), 817 td->td_proc->p_pid, cred); 818 } 819 820 int 821 fdisp_wait_answ(struct fuse_dispatcher *fdip) 822 { 823 int err = 0; 824 825 fdip->answ_stat = 0; 826 fuse_insert_callback(fdip->tick, fuse_standard_handler); 827 fuse_insert_message(fdip->tick); 828 829 if ((err = fticket_wait_answer(fdip->tick))) { 830 debug_printf("IPC: interrupted, err = %d\n", err); 831 832 fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx); 833 834 if (fticket_answered(fdip->tick)) { 835 /* 836 * Just between noticing the interrupt and getting here, 837 * the standard handler has completed his job. 838 * So we drop the ticket and exit as usual. 839 */ 840 debug_printf("IPC: already answered\n"); 841 fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx); 842 goto out; 843 } else { 844 /* 845 * So we were faster than the standard handler. 846 * Then by setting the answered flag we get *him* 847 * to drop the ticket. 848 */ 849 debug_printf("IPC: setting to answered\n"); 850 fticket_set_answered(fdip->tick); 851 fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx); 852 return err; 853 } 854 } 855 debug_printf("IPC: not interrupted, err = %d\n", err); 856 857 if (fdip->tick->tk_aw_errno) { 858 debug_printf("IPC: explicit EIO-ing, tk_aw_errno = %d\n", 859 fdip->tick->tk_aw_errno); 860 err = EIO; 861 goto out; 862 } 863 if ((err = fdip->tick->tk_aw_ohead.error)) { 864 debug_printf("IPC: setting status to %d\n", 865 fdip->tick->tk_aw_ohead.error); 866 /* 867 * This means a "proper" fuse syscall error. 868 * We record this value so the caller will 869 * be able to know it's not a boring messaging 870 * failure, if she wishes so (and if not, she can 871 * just simply propagate the return value of this routine). 872 * [XXX Maybe a bitflag would do the job too, 873 * if other flags needed, this will be converted thusly.] 874 */ 875 fdip->answ_stat = err; 876 goto out; 877 } 878 fdip->answ = fticket_resp(fdip->tick)->base; 879 fdip->iosize = fticket_resp(fdip->tick)->len; 880 881 debug_printf("IPC: all is well\n"); 882 883 return 0; 884 885 out: 886 debug_printf("IPC: dropping ticket, err = %d\n", err); 887 888 return err; 889 } 890 891 void 892 fuse_ipc_init(void) 893 { 894 ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket), 895 fticket_ctor, fticket_dtor, fticket_init, fticket_fini, 896 UMA_ALIGN_PTR, 0); 897 } 898 899 void 900 fuse_ipc_destroy(void) 901 { 902 uma_zdestroy(ticket_zone); 903 } 904