1 /* $NetBSD: genfs_vnops.c,v 1.192 2014/03/24 13:42:40 hannken 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.192 2014/03/24 13:42:40 hannken 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.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_WILLUNLOCK: 231 VOP_UNLOCK(vp); 232 break; 233 case VDESC_VP0_WILLRELE: 234 vrele(vp); 235 break; 236 } 237 } 238 } 239 240 return (EOPNOTSUPP); 241 } 242 243 /*ARGSUSED*/ 244 int 245 genfs_ebadf(void *v) 246 { 247 248 return (EBADF); 249 } 250 251 /* ARGSUSED */ 252 int 253 genfs_enoioctl(void *v) 254 { 255 256 return (EPASSTHROUGH); 257 } 258 259 260 /* 261 * Eliminate all activity associated with the requested vnode 262 * and with all vnodes aliased to the requested vnode. 263 */ 264 int 265 genfs_revoke(void *v) 266 { 267 struct vop_revoke_args /* { 268 struct vnode *a_vp; 269 int a_flags; 270 } */ *ap = v; 271 272 #ifdef DIAGNOSTIC 273 if ((ap->a_flags & REVOKEALL) == 0) 274 panic("genfs_revoke: not revokeall"); 275 #endif 276 vrevoke(ap->a_vp); 277 return (0); 278 } 279 280 /* 281 * Lock the node (for deadfs). 282 */ 283 int 284 genfs_deadlock(void *v) 285 { 286 struct vop_lock_args /* { 287 struct vnode *a_vp; 288 int a_flags; 289 } */ *ap = v; 290 struct vnode *vp = ap->a_vp; 291 int flags = ap->a_flags; 292 krw_t op; 293 int error; 294 295 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER); 296 if (ISSET(flags, LK_NOWAIT)) { 297 if (! rw_tryenter(&vp->v_lock, op)) 298 return EBUSY; 299 if (mutex_tryenter(vp->v_interlock)) { 300 error = vdead_check(vp, VDEAD_NOWAIT); 301 if (error == ENOENT && ISSET(flags, LK_RETRY)) 302 error = 0; 303 mutex_exit(vp->v_interlock); 304 } else 305 error = EBUSY; 306 if (error) 307 rw_exit(&vp->v_lock); 308 return error; 309 } 310 311 rw_enter(&vp->v_lock, op); 312 mutex_enter(vp->v_interlock); 313 error = vdead_check(vp, VDEAD_NOWAIT); 314 if (error == EBUSY) { 315 rw_exit(&vp->v_lock); 316 error = vdead_check(vp, 0); 317 KASSERT(error == ENOENT); 318 mutex_exit(vp->v_interlock); 319 rw_enter(&vp->v_lock, op); 320 mutex_enter(vp->v_interlock); 321 } 322 KASSERT(error == ENOENT); 323 mutex_exit(vp->v_interlock); 324 if (! ISSET(flags, LK_RETRY)) { 325 rw_exit(&vp->v_lock); 326 return ENOENT; 327 } 328 return 0; 329 } 330 331 /* 332 * Unlock the node (for deadfs). 333 */ 334 int 335 genfs_deadunlock(void *v) 336 { 337 struct vop_unlock_args /* { 338 struct vnode *a_vp; 339 } */ *ap = v; 340 struct vnode *vp = ap->a_vp; 341 342 rw_exit(&vp->v_lock); 343 344 return 0; 345 } 346 347 /* 348 * Lock the node. 349 */ 350 int 351 genfs_lock(void *v) 352 { 353 struct vop_lock_args /* { 354 struct vnode *a_vp; 355 int a_flags; 356 } */ *ap = v; 357 struct vnode *vp = ap->a_vp; 358 struct mount *mp = vp->v_mount; 359 int flags = ap->a_flags; 360 krw_t op; 361 int error; 362 363 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER); 364 if (ISSET(flags, LK_NOWAIT)) { 365 if (fstrans_start_nowait(mp, FSTRANS_SHARED)) 366 return EBUSY; 367 if (! rw_tryenter(&vp->v_lock, op)) { 368 fstrans_done(mp); 369 return EBUSY; 370 } 371 if (mutex_tryenter(vp->v_interlock)) { 372 error = vdead_check(vp, VDEAD_NOWAIT); 373 mutex_exit(vp->v_interlock); 374 } else 375 error = EBUSY; 376 if (error) { 377 rw_exit(&vp->v_lock); 378 fstrans_done(mp); 379 } 380 return error; 381 } 382 383 fstrans_start(mp, FSTRANS_SHARED); 384 rw_enter(&vp->v_lock, op); 385 mutex_enter(vp->v_interlock); 386 error = vdead_check(vp, VDEAD_NOWAIT); 387 if (error) { 388 rw_exit(&vp->v_lock); 389 fstrans_done(mp); 390 error = vdead_check(vp, 0); 391 KASSERT(error == ENOENT); 392 } 393 mutex_exit(vp->v_interlock); 394 return error; 395 } 396 397 /* 398 * Unlock the node. 399 */ 400 int 401 genfs_unlock(void *v) 402 { 403 struct vop_unlock_args /* { 404 struct vnode *a_vp; 405 } */ *ap = v; 406 struct vnode *vp = ap->a_vp; 407 struct mount *mp = vp->v_mount; 408 409 rw_exit(&vp->v_lock); 410 fstrans_done(mp); 411 412 return 0; 413 } 414 415 /* 416 * Return whether or not the node is locked. 417 */ 418 int 419 genfs_islocked(void *v) 420 { 421 struct vop_islocked_args /* { 422 struct vnode *a_vp; 423 } */ *ap = v; 424 struct vnode *vp = ap->a_vp; 425 426 if (rw_write_held(&vp->v_lock)) 427 return LK_EXCLUSIVE; 428 429 if (rw_read_held(&vp->v_lock)) 430 return LK_SHARED; 431 432 return 0; 433 } 434 435 /* 436 * Stubs to use when there is no locking to be done on the underlying object. 437 */ 438 int 439 genfs_nolock(void *v) 440 { 441 442 return (0); 443 } 444 445 int 446 genfs_nounlock(void *v) 447 { 448 449 return (0); 450 } 451 452 int 453 genfs_noislocked(void *v) 454 { 455 456 return (0); 457 } 458 459 int 460 genfs_mmap(void *v) 461 { 462 463 return (0); 464 } 465 466 /* 467 * VOP_PUTPAGES() for vnodes which never have pages. 468 */ 469 470 int 471 genfs_null_putpages(void *v) 472 { 473 struct vop_putpages_args /* { 474 struct vnode *a_vp; 475 voff_t a_offlo; 476 voff_t a_offhi; 477 int a_flags; 478 } */ *ap = v; 479 struct vnode *vp = ap->a_vp; 480 481 KASSERT(vp->v_uobj.uo_npages == 0); 482 mutex_exit(vp->v_interlock); 483 return (0); 484 } 485 486 void 487 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops) 488 { 489 struct genfs_node *gp = VTOG(vp); 490 491 rw_init(&gp->g_glock); 492 gp->g_op = ops; 493 } 494 495 void 496 genfs_node_destroy(struct vnode *vp) 497 { 498 struct genfs_node *gp = VTOG(vp); 499 500 rw_destroy(&gp->g_glock); 501 } 502 503 void 504 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 505 { 506 int bsize; 507 508 bsize = 1 << vp->v_mount->mnt_fs_bshift; 509 *eobp = (size + bsize - 1) & ~(bsize - 1); 510 } 511 512 static void 513 filt_genfsdetach(struct knote *kn) 514 { 515 struct vnode *vp = (struct vnode *)kn->kn_hook; 516 517 mutex_enter(vp->v_interlock); 518 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext); 519 mutex_exit(vp->v_interlock); 520 } 521 522 static int 523 filt_genfsread(struct knote *kn, long hint) 524 { 525 struct vnode *vp = (struct vnode *)kn->kn_hook; 526 int rv; 527 528 /* 529 * filesystem is gone, so set the EOF flag and schedule 530 * the knote for deletion. 531 */ 532 switch (hint) { 533 case NOTE_REVOKE: 534 KASSERT(mutex_owned(vp->v_interlock)); 535 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 536 return (1); 537 case 0: 538 mutex_enter(vp->v_interlock); 539 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 540 rv = (kn->kn_data != 0); 541 mutex_exit(vp->v_interlock); 542 return rv; 543 default: 544 KASSERT(mutex_owned(vp->v_interlock)); 545 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 546 return (kn->kn_data != 0); 547 } 548 } 549 550 static int 551 filt_genfsvnode(struct knote *kn, long hint) 552 { 553 struct vnode *vp = (struct vnode *)kn->kn_hook; 554 int fflags; 555 556 switch (hint) { 557 case NOTE_REVOKE: 558 KASSERT(mutex_owned(vp->v_interlock)); 559 kn->kn_flags |= EV_EOF; 560 if ((kn->kn_sfflags & hint) != 0) 561 kn->kn_fflags |= hint; 562 return (1); 563 case 0: 564 mutex_enter(vp->v_interlock); 565 fflags = kn->kn_fflags; 566 mutex_exit(vp->v_interlock); 567 break; 568 default: 569 KASSERT(mutex_owned(vp->v_interlock)); 570 if ((kn->kn_sfflags & hint) != 0) 571 kn->kn_fflags |= hint; 572 fflags = kn->kn_fflags; 573 break; 574 } 575 576 return (fflags != 0); 577 } 578 579 static const struct filterops genfsread_filtops = 580 { 1, NULL, filt_genfsdetach, filt_genfsread }; 581 static const struct filterops genfsvnode_filtops = 582 { 1, NULL, filt_genfsdetach, filt_genfsvnode }; 583 584 int 585 genfs_kqfilter(void *v) 586 { 587 struct vop_kqfilter_args /* { 588 struct vnode *a_vp; 589 struct knote *a_kn; 590 } */ *ap = v; 591 struct vnode *vp; 592 struct knote *kn; 593 594 vp = ap->a_vp; 595 kn = ap->a_kn; 596 switch (kn->kn_filter) { 597 case EVFILT_READ: 598 kn->kn_fop = &genfsread_filtops; 599 break; 600 case EVFILT_VNODE: 601 kn->kn_fop = &genfsvnode_filtops; 602 break; 603 default: 604 return (EINVAL); 605 } 606 607 kn->kn_hook = vp; 608 609 mutex_enter(vp->v_interlock); 610 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext); 611 mutex_exit(vp->v_interlock); 612 613 return (0); 614 } 615 616 void 617 genfs_node_wrlock(struct vnode *vp) 618 { 619 struct genfs_node *gp = VTOG(vp); 620 621 rw_enter(&gp->g_glock, RW_WRITER); 622 } 623 624 void 625 genfs_node_rdlock(struct vnode *vp) 626 { 627 struct genfs_node *gp = VTOG(vp); 628 629 rw_enter(&gp->g_glock, RW_READER); 630 } 631 632 int 633 genfs_node_rdtrylock(struct vnode *vp) 634 { 635 struct genfs_node *gp = VTOG(vp); 636 637 return rw_tryenter(&gp->g_glock, RW_READER); 638 } 639 640 void 641 genfs_node_unlock(struct vnode *vp) 642 { 643 struct genfs_node *gp = VTOG(vp); 644 645 rw_exit(&gp->g_glock); 646 } 647 648 int 649 genfs_node_wrlocked(struct vnode *vp) 650 { 651 struct genfs_node *gp = VTOG(vp); 652 653 return rw_write_held(&gp->g_glock); 654 } 655 656 /* 657 * Do the usual access checking. 658 * file_mode, uid and gid are from the vnode in question, 659 * while acc_mode and cred are from the VOP_ACCESS parameter list 660 */ 661 int 662 genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid, 663 mode_t acc_mode, kauth_cred_t cred) 664 { 665 mode_t mask; 666 int error, ismember; 667 668 mask = 0; 669 670 /* Otherwise, check the owner. */ 671 if (kauth_cred_geteuid(cred) == uid) { 672 if (acc_mode & VEXEC) 673 mask |= S_IXUSR; 674 if (acc_mode & VREAD) 675 mask |= S_IRUSR; 676 if (acc_mode & VWRITE) 677 mask |= S_IWUSR; 678 return ((file_mode & mask) == mask ? 0 : EACCES); 679 } 680 681 /* Otherwise, check the groups. */ 682 error = kauth_cred_ismember_gid(cred, gid, &ismember); 683 if (error) 684 return (error); 685 if (kauth_cred_getegid(cred) == gid || ismember) { 686 if (acc_mode & VEXEC) 687 mask |= S_IXGRP; 688 if (acc_mode & VREAD) 689 mask |= S_IRGRP; 690 if (acc_mode & VWRITE) 691 mask |= S_IWGRP; 692 return ((file_mode & mask) == mask ? 0 : EACCES); 693 } 694 695 /* Otherwise, check everyone else. */ 696 if (acc_mode & VEXEC) 697 mask |= S_IXOTH; 698 if (acc_mode & VREAD) 699 mask |= S_IROTH; 700 if (acc_mode & VWRITE) 701 mask |= S_IWOTH; 702 return ((file_mode & mask) == mask ? 0 : EACCES); 703 } 704 705 /* 706 * Common routine to check if chmod() is allowed. 707 * 708 * Policy: 709 * - You must own the file, and 710 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 711 * - You must be a member of the group if you're trying to set the 712 * SGIDf bit 713 * 714 * cred - credentials of the invoker 715 * vp - vnode of the file-system object 716 * cur_uid, cur_gid - current uid/gid of the file-system object 717 * new_mode - new mode for the file-system object 718 * 719 * Returns 0 if the change is allowed, or an error value otherwise. 720 */ 721 int 722 genfs_can_chmod(enum vtype type, kauth_cred_t cred, uid_t cur_uid, 723 gid_t cur_gid, mode_t new_mode) 724 { 725 int error; 726 727 /* The user must own the file. */ 728 if (kauth_cred_geteuid(cred) != cur_uid) 729 return (EPERM); 730 731 /* 732 * Unprivileged users can't set the sticky bit on files. 733 */ 734 if ((type != VDIR) && (new_mode & S_ISTXT)) 735 return (EFTYPE); 736 737 /* 738 * If the invoker is trying to set the SGID bit on the file, 739 * check group membership. 740 */ 741 if (new_mode & S_ISGID) { 742 int ismember; 743 744 error = kauth_cred_ismember_gid(cred, cur_gid, 745 &ismember); 746 if (error || !ismember) 747 return (EPERM); 748 } 749 750 return (0); 751 } 752 753 /* 754 * Common routine to check if chown() is allowed. 755 * 756 * Policy: 757 * - You must own the file, and 758 * - You must not try to change ownership, and 759 * - You must be member of the new group 760 * 761 * cred - credentials of the invoker 762 * cur_uid, cur_gid - current uid/gid of the file-system object 763 * new_uid, new_gid - target uid/gid of the file-system object 764 * 765 * Returns 0 if the change is allowed, or an error value otherwise. 766 */ 767 int 768 genfs_can_chown(kauth_cred_t cred, uid_t cur_uid, 769 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 770 { 771 int error, ismember; 772 773 /* 774 * You can only change ownership of a file if: 775 * You own the file and... 776 */ 777 if (kauth_cred_geteuid(cred) == cur_uid) { 778 /* 779 * You don't try to change ownership, and... 780 */ 781 if (new_uid != cur_uid) 782 return (EPERM); 783 784 /* 785 * You don't try to change group (no-op), or... 786 */ 787 if (new_gid == cur_gid) 788 return (0); 789 790 /* 791 * Your effective gid is the new gid, or... 792 */ 793 if (kauth_cred_getegid(cred) == new_gid) 794 return (0); 795 796 /* 797 * The new gid is one you're a member of. 798 */ 799 ismember = 0; 800 error = kauth_cred_ismember_gid(cred, new_gid, 801 &ismember); 802 if (!error && ismember) 803 return (0); 804 } 805 806 return (EPERM); 807 } 808 809 int 810 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid, 811 kauth_cred_t cred) 812 { 813 int error; 814 815 /* Must be owner, or... */ 816 if (kauth_cred_geteuid(cred) == owner_uid) 817 return (0); 818 819 /* set the times to the current time, and... */ 820 if ((vaflags & VA_UTIMES_NULL) == 0) 821 return (EPERM); 822 823 /* have write access. */ 824 error = VOP_ACCESS(vp, VWRITE, cred); 825 if (error) 826 return (error); 827 828 return (0); 829 } 830 831 /* 832 * Common routine to check if chflags() is allowed. 833 * 834 * Policy: 835 * - You must own the file, and 836 * - You must not change system flags, and 837 * - You must not change flags on character/block devices. 838 * 839 * cred - credentials of the invoker 840 * owner_uid - uid of the file-system object 841 * changing_sysflags - true if the invoker wants to change system flags 842 */ 843 int 844 genfs_can_chflags(kauth_cred_t cred, enum vtype type, uid_t owner_uid, 845 bool changing_sysflags) 846 { 847 848 /* The user must own the file. */ 849 if (kauth_cred_geteuid(cred) != owner_uid) { 850 return EPERM; 851 } 852 853 if (changing_sysflags) { 854 return EPERM; 855 } 856 857 /* 858 * Unprivileged users cannot change the flags on devices, even if they 859 * own them. 860 */ 861 if (type == VCHR || type == VBLK) { 862 return EPERM; 863 } 864 865 return 0; 866 } 867 868 /* 869 * Common "sticky" policy. 870 * 871 * When a directory is "sticky" (as determined by the caller), this 872 * function may help implementing the following policy: 873 * - Renaming a file in it is only possible if the user owns the directory 874 * or the file being renamed. 875 * - Deleting a file from it is only possible if the user owns the 876 * directory or the file being deleted. 877 */ 878 int 879 genfs_can_sticky(kauth_cred_t cred, uid_t dir_uid, uid_t file_uid) 880 { 881 if (kauth_cred_geteuid(cred) != dir_uid && 882 kauth_cred_geteuid(cred) != file_uid) 883 return EPERM; 884 885 return 0; 886 } 887 888 int 889 genfs_can_extattr(kauth_cred_t cred, int access_mode, vnode_t *vp, 890 const char *attr) 891 { 892 /* We can't allow privileged namespaces. */ 893 if (strncasecmp(attr, "system", 6) == 0) 894 return EPERM; 895 896 return VOP_ACCESS(vp, access_mode, cred); 897 } 898