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