1 /* $NetBSD: genfs_vnops.c,v 1.202 2020/02/23 22:14:04 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 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 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1982, 1986, 1989, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. Neither the name of the University nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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 59 #include <sys/cdefs.h> 60 __KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.202 2020/02/23 22:14:04 ad Exp $"); 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/proc.h> 65 #include <sys/kernel.h> 66 #include <sys/mount.h> 67 #include <sys/fstrans.h> 68 #include <sys/namei.h> 69 #include <sys/vnode_impl.h> 70 #include <sys/fcntl.h> 71 #include <sys/kmem.h> 72 #include <sys/poll.h> 73 #include <sys/mman.h> 74 #include <sys/file.h> 75 #include <sys/kauth.h> 76 #include <sys/stat.h> 77 78 #include <miscfs/genfs/genfs.h> 79 #include <miscfs/genfs/genfs_node.h> 80 #include <miscfs/specfs/specdev.h> 81 82 #include <uvm/uvm.h> 83 #include <uvm/uvm_pager.h> 84 85 static void filt_genfsdetach(struct knote *); 86 static int filt_genfsread(struct knote *, long); 87 static int filt_genfsvnode(struct knote *, long); 88 89 int 90 genfs_poll(void *v) 91 { 92 struct vop_poll_args /* { 93 struct vnode *a_vp; 94 int a_events; 95 struct lwp *a_l; 96 } */ *ap = v; 97 98 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 99 } 100 101 int 102 genfs_seek(void *v) 103 { 104 struct vop_seek_args /* { 105 struct vnode *a_vp; 106 off_t a_oldoff; 107 off_t a_newoff; 108 kauth_cred_t cred; 109 } */ *ap = v; 110 111 if (ap->a_newoff < 0) 112 return (EINVAL); 113 114 return (0); 115 } 116 117 int 118 genfs_abortop(void *v) 119 { 120 struct vop_abortop_args /* { 121 struct vnode *a_dvp; 122 struct componentname *a_cnp; 123 } */ *ap = v; 124 125 (void)ap; 126 127 return (0); 128 } 129 130 int 131 genfs_fcntl(void *v) 132 { 133 struct vop_fcntl_args /* { 134 struct vnode *a_vp; 135 u_int a_command; 136 void *a_data; 137 int a_fflag; 138 kauth_cred_t a_cred; 139 struct lwp *a_l; 140 } */ *ap = v; 141 142 if (ap->a_command == F_SETFL) 143 return (0); 144 else 145 return (EOPNOTSUPP); 146 } 147 148 /*ARGSUSED*/ 149 int 150 genfs_badop(void *v) 151 { 152 153 panic("genfs: bad op"); 154 } 155 156 /*ARGSUSED*/ 157 int 158 genfs_nullop(void *v) 159 { 160 161 return (0); 162 } 163 164 /*ARGSUSED*/ 165 int 166 genfs_einval(void *v) 167 { 168 169 return (EINVAL); 170 } 171 172 /* 173 * Called when an fs doesn't support a particular vop. 174 * This takes care to vrele, vput, or vunlock passed in vnodes 175 * and calls VOP_ABORTOP for a componentname (in non-rename VOP). 176 */ 177 int 178 genfs_eopnotsupp(void *v) 179 { 180 struct vop_generic_args /* 181 struct vnodeop_desc *a_desc; 182 / * other random data follows, presumably * / 183 } */ *ap = v; 184 struct vnodeop_desc *desc = ap->a_desc; 185 struct vnode *vp, *vp_last = NULL; 186 int flags, i, j, offset_cnp, offset_vp; 187 188 KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET); 189 KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET); 190 191 /* 192 * Abort any componentname that lookup potentially left state in. 193 * 194 * As is logical, componentnames for VOP_RENAME are handled by 195 * the caller of VOP_RENAME. Yay, rename! 196 */ 197 if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET && 198 (offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET && 199 (offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){ 200 struct componentname *cnp; 201 struct vnode *dvp; 202 203 dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 204 cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap); 205 206 VOP_ABORTOP(dvp, cnp); 207 } 208 209 flags = desc->vdesc_flags; 210 for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) { 211 if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET) 212 break; /* stop at end of list */ 213 if ((j = flags & VDESC_VP0_WILLPUT)) { 214 vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 215 216 /* Skip if NULL */ 217 if (!vp) 218 continue; 219 220 switch (j) { 221 case VDESC_VP0_WILLPUT: 222 /* Check for dvp == vp cases */ 223 if (vp == vp_last) 224 vrele(vp); 225 else { 226 vput(vp); 227 vp_last = vp; 228 } 229 break; 230 case VDESC_VP0_WILLRELE: 231 vrele(vp); 232 break; 233 } 234 } 235 } 236 237 return (EOPNOTSUPP); 238 } 239 240 /*ARGSUSED*/ 241 int 242 genfs_ebadf(void *v) 243 { 244 245 return (EBADF); 246 } 247 248 /* ARGSUSED */ 249 int 250 genfs_enoioctl(void *v) 251 { 252 253 return (EPASSTHROUGH); 254 } 255 256 257 /* 258 * Eliminate all activity associated with the requested vnode 259 * and with all vnodes aliased to the requested vnode. 260 */ 261 int 262 genfs_revoke(void *v) 263 { 264 struct vop_revoke_args /* { 265 struct vnode *a_vp; 266 int a_flags; 267 } */ *ap = v; 268 269 #ifdef DIAGNOSTIC 270 if ((ap->a_flags & REVOKEALL) == 0) 271 panic("genfs_revoke: not revokeall"); 272 #endif 273 vrevoke(ap->a_vp); 274 return (0); 275 } 276 277 /* 278 * Lock the node (for deadfs). 279 */ 280 int 281 genfs_deadlock(void *v) 282 { 283 struct vop_lock_args /* { 284 struct vnode *a_vp; 285 int a_flags; 286 } */ *ap = v; 287 vnode_t *vp = ap->a_vp; 288 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 289 int flags = ap->a_flags; 290 krw_t op; 291 292 if (! ISSET(flags, LK_RETRY)) 293 return ENOENT; 294 295 if (ISSET(flags, LK_DOWNGRADE)) { 296 rw_downgrade(&vip->vi_lock); 297 } else if (ISSET(flags, LK_UPGRADE)) { 298 KASSERT(ISSET(flags, LK_NOWAIT)); 299 if (!rw_tryupgrade(&vip->vi_lock)) { 300 return EBUSY; 301 } 302 } else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) { 303 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER); 304 if (ISSET(flags, LK_NOWAIT)) { 305 if (!rw_tryenter(&vip->vi_lock, op)) 306 return EBUSY; 307 } else { 308 rw_enter(&vip->vi_lock, op); 309 } 310 } 311 VSTATE_ASSERT_UNLOCKED(vp, VS_RECLAIMED); 312 return 0; 313 } 314 315 /* 316 * Unlock the node (for deadfs). 317 */ 318 int 319 genfs_deadunlock(void *v) 320 { 321 struct vop_unlock_args /* { 322 struct vnode *a_vp; 323 } */ *ap = v; 324 vnode_t *vp = ap->a_vp; 325 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 326 327 rw_exit(&vip->vi_lock); 328 329 return 0; 330 } 331 332 /* 333 * Lock the node. 334 */ 335 int 336 genfs_lock(void *v) 337 { 338 struct vop_lock_args /* { 339 struct vnode *a_vp; 340 int a_flags; 341 } */ *ap = v; 342 vnode_t *vp = ap->a_vp; 343 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 344 int flags = ap->a_flags; 345 krw_t op; 346 347 if (ISSET(flags, LK_DOWNGRADE)) { 348 rw_downgrade(&vip->vi_lock); 349 } else if (ISSET(flags, LK_UPGRADE)) { 350 KASSERT(ISSET(flags, LK_NOWAIT)); 351 if (!rw_tryupgrade(&vip->vi_lock)) { 352 return EBUSY; 353 } 354 } else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) { 355 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER); 356 if (ISSET(flags, LK_NOWAIT)) { 357 if (!rw_tryenter(&vip->vi_lock, op)) 358 return EBUSY; 359 } else { 360 rw_enter(&vip->vi_lock, op); 361 } 362 } 363 VSTATE_ASSERT_UNLOCKED(vp, VS_ACTIVE); 364 return 0; 365 } 366 367 /* 368 * Unlock the node. 369 */ 370 int 371 genfs_unlock(void *v) 372 { 373 struct vop_unlock_args /* { 374 struct vnode *a_vp; 375 } */ *ap = v; 376 vnode_t *vp = ap->a_vp; 377 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 378 379 rw_exit(&vip->vi_lock); 380 381 return 0; 382 } 383 384 /* 385 * Return whether or not the node is locked. 386 */ 387 int 388 genfs_islocked(void *v) 389 { 390 struct vop_islocked_args /* { 391 struct vnode *a_vp; 392 } */ *ap = v; 393 vnode_t *vp = ap->a_vp; 394 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 395 396 if (rw_write_held(&vip->vi_lock)) 397 return LK_EXCLUSIVE; 398 399 if (rw_read_held(&vip->vi_lock)) 400 return LK_SHARED; 401 402 return 0; 403 } 404 405 /* 406 * Stubs to use when there is no locking to be done on the underlying object. 407 */ 408 int 409 genfs_nolock(void *v) 410 { 411 412 return (0); 413 } 414 415 int 416 genfs_nounlock(void *v) 417 { 418 419 return (0); 420 } 421 422 int 423 genfs_noislocked(void *v) 424 { 425 426 return (0); 427 } 428 429 int 430 genfs_mmap(void *v) 431 { 432 433 return (0); 434 } 435 436 /* 437 * VOP_PUTPAGES() for vnodes which never have pages. 438 */ 439 440 int 441 genfs_null_putpages(void *v) 442 { 443 struct vop_putpages_args /* { 444 struct vnode *a_vp; 445 voff_t a_offlo; 446 voff_t a_offhi; 447 int a_flags; 448 } */ *ap = v; 449 struct vnode *vp = ap->a_vp; 450 451 KASSERT(vp->v_uobj.uo_npages == 0); 452 rw_exit(vp->v_uobj.vmobjlock); 453 return (0); 454 } 455 456 void 457 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops) 458 { 459 struct genfs_node *gp = VTOG(vp); 460 461 rw_init(&gp->g_glock); 462 gp->g_op = ops; 463 } 464 465 void 466 genfs_node_destroy(struct vnode *vp) 467 { 468 struct genfs_node *gp = VTOG(vp); 469 470 rw_destroy(&gp->g_glock); 471 } 472 473 void 474 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 475 { 476 int bsize; 477 478 bsize = 1 << vp->v_mount->mnt_fs_bshift; 479 *eobp = (size + bsize - 1) & ~(bsize - 1); 480 } 481 482 static void 483 filt_genfsdetach(struct knote *kn) 484 { 485 struct vnode *vp = (struct vnode *)kn->kn_hook; 486 487 mutex_enter(vp->v_interlock); 488 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext); 489 mutex_exit(vp->v_interlock); 490 } 491 492 static int 493 filt_genfsread(struct knote *kn, long hint) 494 { 495 struct vnode *vp = (struct vnode *)kn->kn_hook; 496 int rv; 497 498 /* 499 * filesystem is gone, so set the EOF flag and schedule 500 * the knote for deletion. 501 */ 502 switch (hint) { 503 case NOTE_REVOKE: 504 KASSERT(mutex_owned(vp->v_interlock)); 505 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 506 return (1); 507 case 0: 508 mutex_enter(vp->v_interlock); 509 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 510 rv = (kn->kn_data != 0); 511 mutex_exit(vp->v_interlock); 512 return rv; 513 default: 514 KASSERT(mutex_owned(vp->v_interlock)); 515 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 516 return (kn->kn_data != 0); 517 } 518 } 519 520 static int 521 filt_genfswrite(struct knote *kn, long hint) 522 { 523 struct vnode *vp = (struct vnode *)kn->kn_hook; 524 525 /* 526 * filesystem is gone, so set the EOF flag and schedule 527 * the knote for deletion. 528 */ 529 switch (hint) { 530 case NOTE_REVOKE: 531 KASSERT(mutex_owned(vp->v_interlock)); 532 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 533 return (1); 534 case 0: 535 mutex_enter(vp->v_interlock); 536 kn->kn_data = 0; 537 mutex_exit(vp->v_interlock); 538 return 1; 539 default: 540 KASSERT(mutex_owned(vp->v_interlock)); 541 kn->kn_data = 0; 542 return 1; 543 } 544 } 545 546 static int 547 filt_genfsvnode(struct knote *kn, long hint) 548 { 549 struct vnode *vp = (struct vnode *)kn->kn_hook; 550 int fflags; 551 552 switch (hint) { 553 case NOTE_REVOKE: 554 KASSERT(mutex_owned(vp->v_interlock)); 555 kn->kn_flags |= EV_EOF; 556 if ((kn->kn_sfflags & hint) != 0) 557 kn->kn_fflags |= hint; 558 return (1); 559 case 0: 560 mutex_enter(vp->v_interlock); 561 fflags = kn->kn_fflags; 562 mutex_exit(vp->v_interlock); 563 break; 564 default: 565 KASSERT(mutex_owned(vp->v_interlock)); 566 if ((kn->kn_sfflags & hint) != 0) 567 kn->kn_fflags |= hint; 568 fflags = kn->kn_fflags; 569 break; 570 } 571 572 return (fflags != 0); 573 } 574 575 static const struct filterops genfsread_filtops = { 576 .f_isfd = 1, 577 .f_attach = NULL, 578 .f_detach = filt_genfsdetach, 579 .f_event = filt_genfsread, 580 }; 581 582 static const struct filterops genfswrite_filtops = { 583 .f_isfd = 1, 584 .f_attach = NULL, 585 .f_detach = filt_genfsdetach, 586 .f_event = filt_genfswrite, 587 }; 588 589 static const struct filterops genfsvnode_filtops = { 590 .f_isfd = 1, 591 .f_attach = NULL, 592 .f_detach = filt_genfsdetach, 593 .f_event = filt_genfsvnode, 594 }; 595 596 int 597 genfs_kqfilter(void *v) 598 { 599 struct vop_kqfilter_args /* { 600 struct vnode *a_vp; 601 struct knote *a_kn; 602 } */ *ap = v; 603 struct vnode *vp; 604 struct knote *kn; 605 606 vp = ap->a_vp; 607 kn = ap->a_kn; 608 switch (kn->kn_filter) { 609 case EVFILT_READ: 610 kn->kn_fop = &genfsread_filtops; 611 break; 612 case EVFILT_WRITE: 613 kn->kn_fop = &genfswrite_filtops; 614 break; 615 case EVFILT_VNODE: 616 kn->kn_fop = &genfsvnode_filtops; 617 break; 618 default: 619 return (EINVAL); 620 } 621 622 kn->kn_hook = vp; 623 624 mutex_enter(vp->v_interlock); 625 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext); 626 mutex_exit(vp->v_interlock); 627 628 return (0); 629 } 630 631 void 632 genfs_node_wrlock(struct vnode *vp) 633 { 634 struct genfs_node *gp = VTOG(vp); 635 636 rw_enter(&gp->g_glock, RW_WRITER); 637 } 638 639 void 640 genfs_node_rdlock(struct vnode *vp) 641 { 642 struct genfs_node *gp = VTOG(vp); 643 644 rw_enter(&gp->g_glock, RW_READER); 645 } 646 647 int 648 genfs_node_rdtrylock(struct vnode *vp) 649 { 650 struct genfs_node *gp = VTOG(vp); 651 652 return rw_tryenter(&gp->g_glock, RW_READER); 653 } 654 655 void 656 genfs_node_unlock(struct vnode *vp) 657 { 658 struct genfs_node *gp = VTOG(vp); 659 660 rw_exit(&gp->g_glock); 661 } 662 663 int 664 genfs_node_wrlocked(struct vnode *vp) 665 { 666 struct genfs_node *gp = VTOG(vp); 667 668 return rw_write_held(&gp->g_glock); 669 } 670 671 /* 672 * Do the usual access checking. 673 * file_mode, uid and gid are from the vnode in question, 674 * while acc_mode and cred are from the VOP_ACCESS parameter list 675 */ 676 int 677 genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid, 678 mode_t acc_mode, kauth_cred_t cred) 679 { 680 mode_t mask; 681 int error, ismember; 682 683 mask = 0; 684 685 /* Otherwise, check the owner. */ 686 if (kauth_cred_geteuid(cred) == uid) { 687 if (acc_mode & VEXEC) 688 mask |= S_IXUSR; 689 if (acc_mode & VREAD) 690 mask |= S_IRUSR; 691 if (acc_mode & VWRITE) 692 mask |= S_IWUSR; 693 return ((file_mode & mask) == mask ? 0 : EACCES); 694 } 695 696 /* Otherwise, check the groups. */ 697 error = kauth_cred_ismember_gid(cred, gid, &ismember); 698 if (error) 699 return (error); 700 if (kauth_cred_getegid(cred) == gid || ismember) { 701 if (acc_mode & VEXEC) 702 mask |= S_IXGRP; 703 if (acc_mode & VREAD) 704 mask |= S_IRGRP; 705 if (acc_mode & VWRITE) 706 mask |= S_IWGRP; 707 return ((file_mode & mask) == mask ? 0 : EACCES); 708 } 709 710 /* Otherwise, check everyone else. */ 711 if (acc_mode & VEXEC) 712 mask |= S_IXOTH; 713 if (acc_mode & VREAD) 714 mask |= S_IROTH; 715 if (acc_mode & VWRITE) 716 mask |= S_IWOTH; 717 return ((file_mode & mask) == mask ? 0 : EACCES); 718 } 719 720 /* 721 * Common routine to check if chmod() is allowed. 722 * 723 * Policy: 724 * - You must own the file, and 725 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 726 * - You must be a member of the group if you're trying to set the 727 * SGIDf bit 728 * 729 * cred - credentials of the invoker 730 * vp - vnode of the file-system object 731 * cur_uid, cur_gid - current uid/gid of the file-system object 732 * new_mode - new mode for the file-system object 733 * 734 * Returns 0 if the change is allowed, or an error value otherwise. 735 */ 736 int 737 genfs_can_chmod(enum vtype type, kauth_cred_t cred, uid_t cur_uid, 738 gid_t cur_gid, mode_t new_mode) 739 { 740 int error; 741 742 /* The user must own the file. */ 743 if (kauth_cred_geteuid(cred) != cur_uid) 744 return (EPERM); 745 746 /* 747 * Unprivileged users can't set the sticky bit on files. 748 */ 749 if ((type != VDIR) && (new_mode & S_ISTXT)) 750 return (EFTYPE); 751 752 /* 753 * If the invoker is trying to set the SGID bit on the file, 754 * check group membership. 755 */ 756 if (new_mode & S_ISGID) { 757 int ismember; 758 759 error = kauth_cred_ismember_gid(cred, cur_gid, 760 &ismember); 761 if (error || !ismember) 762 return (EPERM); 763 } 764 765 return (0); 766 } 767 768 /* 769 * Common routine to check if chown() is allowed. 770 * 771 * Policy: 772 * - You must own the file, and 773 * - You must not try to change ownership, and 774 * - You must be member of the new group 775 * 776 * cred - credentials of the invoker 777 * cur_uid, cur_gid - current uid/gid of the file-system object 778 * new_uid, new_gid - target uid/gid of the file-system object 779 * 780 * Returns 0 if the change is allowed, or an error value otherwise. 781 */ 782 int 783 genfs_can_chown(kauth_cred_t cred, uid_t cur_uid, 784 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 785 { 786 int error, ismember; 787 788 /* 789 * You can only change ownership of a file if: 790 * You own the file and... 791 */ 792 if (kauth_cred_geteuid(cred) == cur_uid) { 793 /* 794 * You don't try to change ownership, and... 795 */ 796 if (new_uid != cur_uid) 797 return (EPERM); 798 799 /* 800 * You don't try to change group (no-op), or... 801 */ 802 if (new_gid == cur_gid) 803 return (0); 804 805 /* 806 * Your effective gid is the new gid, or... 807 */ 808 if (kauth_cred_getegid(cred) == new_gid) 809 return (0); 810 811 /* 812 * The new gid is one you're a member of. 813 */ 814 ismember = 0; 815 error = kauth_cred_ismember_gid(cred, new_gid, 816 &ismember); 817 if (!error && ismember) 818 return (0); 819 } 820 821 return (EPERM); 822 } 823 824 int 825 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid, 826 kauth_cred_t cred) 827 { 828 int error; 829 830 /* Must be owner, or... */ 831 if (kauth_cred_geteuid(cred) == owner_uid) 832 return (0); 833 834 /* set the times to the current time, and... */ 835 if ((vaflags & VA_UTIMES_NULL) == 0) 836 return (EPERM); 837 838 /* have write access. */ 839 error = VOP_ACCESS(vp, VWRITE, cred); 840 if (error) 841 return (error); 842 843 return (0); 844 } 845 846 /* 847 * Common routine to check if chflags() is allowed. 848 * 849 * Policy: 850 * - You must own the file, and 851 * - You must not change system flags, and 852 * - You must not change flags on character/block devices. 853 * 854 * cred - credentials of the invoker 855 * owner_uid - uid of the file-system object 856 * changing_sysflags - true if the invoker wants to change system flags 857 */ 858 int 859 genfs_can_chflags(kauth_cred_t cred, enum vtype type, uid_t owner_uid, 860 bool changing_sysflags) 861 { 862 863 /* The user must own the file. */ 864 if (kauth_cred_geteuid(cred) != owner_uid) { 865 return EPERM; 866 } 867 868 if (changing_sysflags) { 869 return EPERM; 870 } 871 872 /* 873 * Unprivileged users cannot change the flags on devices, even if they 874 * own them. 875 */ 876 if (type == VCHR || type == VBLK) { 877 return EPERM; 878 } 879 880 return 0; 881 } 882 883 /* 884 * Common "sticky" policy. 885 * 886 * When a directory is "sticky" (as determined by the caller), this 887 * function may help implementing the following policy: 888 * - Renaming a file in it is only possible if the user owns the directory 889 * or the file being renamed. 890 * - Deleting a file from it is only possible if the user owns the 891 * directory or the file being deleted. 892 */ 893 int 894 genfs_can_sticky(kauth_cred_t cred, uid_t dir_uid, uid_t file_uid) 895 { 896 if (kauth_cred_geteuid(cred) != dir_uid && 897 kauth_cred_geteuid(cred) != file_uid) 898 return EPERM; 899 900 return 0; 901 } 902 903 int 904 genfs_can_extattr(kauth_cred_t cred, int access_mode, vnode_t *vp, 905 const char *attr) 906 { 907 /* We can't allow privileged namespaces. */ 908 if (strncasecmp(attr, "system", 6) == 0) 909 return EPERM; 910 911 return VOP_ACCESS(vp, access_mode, cred); 912 } 913