1 /*        $NetBSD: genfs_vnops.c,v 1.220 2023/03/03 10:02:51 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.220 2023/03/03 10:02:51 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_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 #include <sys/extattr.h>
78 
79 #include <miscfs/genfs/genfs.h>
80 #include <miscfs/genfs/genfs_node.h>
81 #include <miscfs/specfs/specdev.h>
82 
83 static void filt_genfsdetach(struct knote *);
84 static int filt_genfsread(struct knote *, long);
85 static int filt_genfsvnode(struct knote *, long);
86 
87 /*
88  * Find the end of the first path component in NAME and return its
89  * length.
90  */
91 int
genfs_parsepath(void * v)92 genfs_parsepath(void *v)
93 {
94           struct vop_parsepath_args /* {
95                     struct vnode *a_dvp;
96                     const char *a_name;
97                     size_t *a_ret;
98           } */ *ap = v;
99           const char *name = ap->a_name;
100           size_t pos;
101 
102           (void)ap->a_dvp;
103 
104           pos = 0;
105           while (name[pos] != '\0' && name[pos] != '/') {
106                     pos++;
107           }
108           *ap->a_retval = pos;
109           return 0;
110 }
111 
112 int
genfs_poll(void * v)113 genfs_poll(void *v)
114 {
115           struct vop_poll_args /* {
116                     struct vnode *a_vp;
117                     int a_events;
118                     struct lwp *a_l;
119           } */ *ap = v;
120 
121           return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
122 }
123 
124 int
genfs_seek(void * v)125 genfs_seek(void *v)
126 {
127           struct vop_seek_args /* {
128                     struct vnode *a_vp;
129                     off_t a_oldoff;
130                     off_t a_newoff;
131                     kauth_cred_t cred;
132           } */ *ap = v;
133 
134           if (ap->a_newoff < 0)
135                     return (EINVAL);
136 
137           return (0);
138 }
139 
140 int
genfs_abortop(void * v)141 genfs_abortop(void *v)
142 {
143           struct vop_abortop_args /* {
144                     struct vnode *a_dvp;
145                     struct componentname *a_cnp;
146           } */ *ap = v;
147 
148           (void)ap;
149 
150           return (0);
151 }
152 
153 int
genfs_fcntl(void * v)154 genfs_fcntl(void *v)
155 {
156           struct vop_fcntl_args /* {
157                     struct vnode *a_vp;
158                     u_int a_command;
159                     void *a_data;
160                     int a_fflag;
161                     kauth_cred_t a_cred;
162                     struct lwp *a_l;
163           } */ *ap = v;
164 
165           if (ap->a_command == F_SETFL)
166                     return (0);
167           else
168                     return (EOPNOTSUPP);
169 }
170 
171 /*ARGSUSED*/
172 int
genfs_badop(void * v)173 genfs_badop(void *v)
174 {
175 
176           panic("genfs: bad op");
177 }
178 
179 /*ARGSUSED*/
180 int
genfs_nullop(void * v)181 genfs_nullop(void *v)
182 {
183 
184           return (0);
185 }
186 
187 /*ARGSUSED*/
188 int
genfs_einval(void * v)189 genfs_einval(void *v)
190 {
191 
192           return (EINVAL);
193 }
194 
195 int
genfs_erofs_link(void * v)196 genfs_erofs_link(void *v)
197 {
198           /* also for symlink */
199           struct vop_link_v2_args /* {
200                     struct vnode *a_dvp;
201                     struct vnode **a_vpp;
202                     struct componentname *a_cnp;
203           } */ *ap = v;
204 
205           VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
206           return EROFS;
207 }
208 
209 /*
210  * Called when an fs doesn't support a particular vop.
211  * This takes care to vrele, vput, or vunlock passed in vnodes
212  * and calls VOP_ABORTOP for a componentname (in non-rename VOP).
213  */
214 int
genfs_eopnotsupp(void * v)215 genfs_eopnotsupp(void *v)
216 {
217           struct vop_generic_args /*
218                     struct vnodeop_desc *a_desc;
219                     / * other random data follows, presumably * /
220           } */ *ap = v;
221           struct vnodeop_desc *desc = ap->a_desc;
222           struct vnode *vp, *vp_last = NULL;
223           int flags, i, j, offset_cnp, offset_vp;
224 
225           KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET);
226           KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET);
227 
228           /*
229            * Abort any componentname that lookup potentially left state in.
230            *
231            * As is logical, componentnames for VOP_RENAME are handled by
232            * the caller of VOP_RENAME.  Yay, rename!
233            */
234           if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET &&
235               (offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET &&
236               (offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){
237                     struct componentname *cnp;
238                     struct vnode *dvp;
239 
240                     dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
241                     cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap);
242 
243                     VOP_ABORTOP(dvp, cnp);
244           }
245 
246           flags = desc->vdesc_flags;
247           for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
248                     if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
249                               break;    /* stop at end of list */
250                     if ((j = flags & VDESC_VP0_WILLPUT)) {
251                               vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
252 
253                               /* Skip if NULL */
254                               if (!vp)
255                                         continue;
256 
257                               switch (j) {
258                               case VDESC_VP0_WILLPUT:
259                                         /* Check for dvp == vp cases */
260                                         if (vp == vp_last)
261                                                   vrele(vp);
262                                         else {
263                                                   vput(vp);
264                                                   vp_last = vp;
265                                         }
266                                         break;
267                               case VDESC_VP0_WILLRELE:
268                                         vrele(vp);
269                                         break;
270                               }
271                     }
272           }
273 
274           return (EOPNOTSUPP);
275 }
276 
277 /*ARGSUSED*/
278 int
genfs_ebadf(void * v)279 genfs_ebadf(void *v)
280 {
281 
282           return (EBADF);
283 }
284 
285 /* ARGSUSED */
286 int
genfs_enoioctl(void * v)287 genfs_enoioctl(void *v)
288 {
289 
290           return (EPASSTHROUGH);
291 }
292 
293 
294 /*
295  * Eliminate all activity associated with the requested vnode
296  * and with all vnodes aliased to the requested vnode.
297  */
298 int
genfs_revoke(void * v)299 genfs_revoke(void *v)
300 {
301           struct vop_revoke_args /* {
302                     struct vnode *a_vp;
303                     int a_flags;
304           } */ *ap = v;
305 
306 #ifdef DIAGNOSTIC
307           if ((ap->a_flags & REVOKEALL) == 0)
308                     panic("genfs_revoke: not revokeall");
309 #endif
310           vrevoke(ap->a_vp);
311           return (0);
312 }
313 
314 /*
315  * Lock the node (for deadfs).
316  */
317 int
genfs_deadlock(void * v)318 genfs_deadlock(void *v)
319 {
320           struct vop_lock_args /* {
321                     struct vnode *a_vp;
322                     int a_flags;
323           } */ *ap = v;
324           vnode_t *vp = ap->a_vp;
325           vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
326           int flags = ap->a_flags;
327           krw_t op;
328 
329           if (! ISSET(flags, LK_RETRY))
330                     return ENOENT;
331 
332           if (ISSET(flags, LK_DOWNGRADE)) {
333                     rw_downgrade(&vip->vi_lock);
334           } else if (ISSET(flags, LK_UPGRADE)) {
335                     KASSERT(ISSET(flags, LK_NOWAIT));
336                     if (!rw_tryupgrade(&vip->vi_lock)) {
337                               return EBUSY;
338                     }
339           } else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) {
340                     op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER);
341                     if (ISSET(flags, LK_NOWAIT)) {
342                               if (!rw_tryenter(&vip->vi_lock, op))
343                                         return EBUSY;
344                     } else {
345                               rw_enter(&vip->vi_lock, op);
346                     }
347           }
348           VSTATE_ASSERT_UNLOCKED(vp, VS_RECLAIMED);
349           return 0;
350 }
351 
352 /*
353  * Unlock the node (for deadfs).
354  */
355 int
genfs_deadunlock(void * v)356 genfs_deadunlock(void *v)
357 {
358           struct vop_unlock_args /* {
359                     struct vnode *a_vp;
360           } */ *ap = v;
361           vnode_t *vp = ap->a_vp;
362           vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
363 
364           rw_exit(&vip->vi_lock);
365 
366           return 0;
367 }
368 
369 /*
370  * Lock the node.
371  */
372 int
genfs_lock(void * v)373 genfs_lock(void *v)
374 {
375           struct vop_lock_args /* {
376                     struct vnode *a_vp;
377                     int a_flags;
378           } */ *ap = v;
379           vnode_t *vp = ap->a_vp;
380           vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
381           int flags = ap->a_flags;
382           krw_t op;
383 
384           if (ISSET(flags, LK_DOWNGRADE)) {
385                     rw_downgrade(&vip->vi_lock);
386           } else if (ISSET(flags, LK_UPGRADE)) {
387                     KASSERT(ISSET(flags, LK_NOWAIT));
388                     if (!rw_tryupgrade(&vip->vi_lock)) {
389                               return EBUSY;
390                     }
391           } else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) {
392                     op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER);
393                     if (ISSET(flags, LK_NOWAIT)) {
394                               if (!rw_tryenter(&vip->vi_lock, op))
395                                         return EBUSY;
396                     } else {
397                               rw_enter(&vip->vi_lock, op);
398                     }
399           }
400           VSTATE_ASSERT_UNLOCKED(vp, VS_ACTIVE);
401           return 0;
402 }
403 
404 /*
405  * Unlock the node.
406  */
407 int
genfs_unlock(void * v)408 genfs_unlock(void *v)
409 {
410           struct vop_unlock_args /* {
411                     struct vnode *a_vp;
412           } */ *ap = v;
413           vnode_t *vp = ap->a_vp;
414           vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
415 
416           rw_exit(&vip->vi_lock);
417 
418           return 0;
419 }
420 
421 /*
422  * Return whether or not the node is locked.
423  */
424 int
genfs_islocked(void * v)425 genfs_islocked(void *v)
426 {
427           struct vop_islocked_args /* {
428                     struct vnode *a_vp;
429           } */ *ap = v;
430           vnode_t *vp = ap->a_vp;
431           vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
432 
433           if (rw_write_held(&vip->vi_lock))
434                     return LK_EXCLUSIVE;
435 
436           if (rw_read_held(&vip->vi_lock))
437                     return LK_SHARED;
438 
439           return 0;
440 }
441 
442 int
genfs_mmap(void * v)443 genfs_mmap(void *v)
444 {
445 
446           return (0);
447 }
448 
449 /*
450  * VOP_PUTPAGES() for vnodes which never have pages.
451  */
452 
453 int
genfs_null_putpages(void * v)454 genfs_null_putpages(void *v)
455 {
456           struct vop_putpages_args /* {
457                     struct vnode *a_vp;
458                     voff_t a_offlo;
459                     voff_t a_offhi;
460                     int a_flags;
461           } */ *ap = v;
462           struct vnode *vp = ap->a_vp;
463 
464           KASSERT(vp->v_uobj.uo_npages == 0);
465           rw_exit(vp->v_uobj.vmobjlock);
466           return (0);
467 }
468 
469 void
genfs_node_init(struct vnode * vp,const struct genfs_ops * ops)470 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
471 {
472           struct genfs_node *gp = VTOG(vp);
473 
474           rw_init(&gp->g_glock);
475           gp->g_op = ops;
476 }
477 
478 void
genfs_node_destroy(struct vnode * vp)479 genfs_node_destroy(struct vnode *vp)
480 {
481           struct genfs_node *gp = VTOG(vp);
482 
483           rw_destroy(&gp->g_glock);
484 }
485 
486 void
genfs_size(struct vnode * vp,off_t size,off_t * eobp,int flags)487 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
488 {
489           int bsize;
490 
491           bsize = 1 << vp->v_mount->mnt_fs_bshift;
492           *eobp = (size + bsize - 1) & ~(bsize - 1);
493 }
494 
495 static void
filt_genfsdetach(struct knote * kn)496 filt_genfsdetach(struct knote *kn)
497 {
498           struct vnode *vp = (struct vnode *)kn->kn_hook;
499 
500           vn_knote_detach(vp, kn);
501 }
502 
503 static int
filt_genfsread(struct knote * kn,long hint)504 filt_genfsread(struct knote *kn, long hint)
505 {
506           struct vnode *vp = (struct vnode *)kn->kn_hook;
507           int rv;
508 
509           /*
510            * filesystem is gone, so set the EOF flag and schedule
511            * the knote for deletion.
512            */
513           switch (hint) {
514           case NOTE_REVOKE:
515                     KASSERT(mutex_owned(vp->v_interlock));
516                     knote_set_eof(kn, EV_ONESHOT);
517                     return (1);
518           case 0:
519                     mutex_enter(vp->v_interlock);
520                     kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
521                     rv = (kn->kn_data != 0);
522                     mutex_exit(vp->v_interlock);
523                     return rv;
524           default:
525                     KASSERT(mutex_owned(vp->v_interlock));
526                     kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
527                     return (kn->kn_data != 0);
528           }
529 }
530 
531 static int
filt_genfswrite(struct knote * kn,long hint)532 filt_genfswrite(struct knote *kn, long hint)
533 {
534           struct vnode *vp = (struct vnode *)kn->kn_hook;
535 
536           /*
537            * filesystem is gone, so set the EOF flag and schedule
538            * the knote for deletion.
539            */
540           switch (hint) {
541           case NOTE_REVOKE:
542                     KASSERT(mutex_owned(vp->v_interlock));
543                     knote_set_eof(kn, EV_ONESHOT);
544                     return (1);
545           case 0:
546                     mutex_enter(vp->v_interlock);
547                     kn->kn_data = 0;
548                     mutex_exit(vp->v_interlock);
549                     return 1;
550           default:
551                     KASSERT(mutex_owned(vp->v_interlock));
552                     kn->kn_data = 0;
553                     return 1;
554           }
555 }
556 
557 static int
filt_genfsvnode(struct knote * kn,long hint)558 filt_genfsvnode(struct knote *kn, long hint)
559 {
560           struct vnode *vp = (struct vnode *)kn->kn_hook;
561           int fflags;
562 
563           switch (hint) {
564           case NOTE_REVOKE:
565                     KASSERT(mutex_owned(vp->v_interlock));
566                     knote_set_eof(kn, 0);
567                     if ((kn->kn_sfflags & hint) != 0)
568                               kn->kn_fflags |= hint;
569                     return (1);
570           case 0:
571                     mutex_enter(vp->v_interlock);
572                     fflags = kn->kn_fflags;
573                     mutex_exit(vp->v_interlock);
574                     break;
575           default:
576                     KASSERT(mutex_owned(vp->v_interlock));
577                     if ((kn->kn_sfflags & hint) != 0)
578                               kn->kn_fflags |= hint;
579                     fflags = kn->kn_fflags;
580                     break;
581           }
582 
583           return (fflags != 0);
584 }
585 
586 static const struct filterops genfsread_filtops = {
587           .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
588           .f_attach = NULL,
589           .f_detach = filt_genfsdetach,
590           .f_event = filt_genfsread,
591 };
592 
593 static const struct filterops genfswrite_filtops = {
594           .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
595           .f_attach = NULL,
596           .f_detach = filt_genfsdetach,
597           .f_event = filt_genfswrite,
598 };
599 
600 static const struct filterops genfsvnode_filtops = {
601           .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
602           .f_attach = NULL,
603           .f_detach = filt_genfsdetach,
604           .f_event = filt_genfsvnode,
605 };
606 
607 int
genfs_kqfilter(void * v)608 genfs_kqfilter(void *v)
609 {
610           struct vop_kqfilter_args /* {
611                     struct vnode        *a_vp;
612                     struct knote        *a_kn;
613           } */ *ap = v;
614           struct vnode *vp;
615           struct knote *kn;
616 
617           vp = ap->a_vp;
618           kn = ap->a_kn;
619           switch (kn->kn_filter) {
620           case EVFILT_READ:
621                     kn->kn_fop = &genfsread_filtops;
622                     break;
623           case EVFILT_WRITE:
624                     kn->kn_fop = &genfswrite_filtops;
625                     break;
626           case EVFILT_VNODE:
627                     kn->kn_fop = &genfsvnode_filtops;
628                     break;
629           default:
630                     return (EINVAL);
631           }
632 
633           kn->kn_hook = vp;
634 
635           vn_knote_attach(vp, kn);
636 
637           return (0);
638 }
639 
640 void
genfs_node_wrlock(struct vnode * vp)641 genfs_node_wrlock(struct vnode *vp)
642 {
643           struct genfs_node *gp = VTOG(vp);
644 
645           rw_enter(&gp->g_glock, RW_WRITER);
646 }
647 
648 void
genfs_node_rdlock(struct vnode * vp)649 genfs_node_rdlock(struct vnode *vp)
650 {
651           struct genfs_node *gp = VTOG(vp);
652 
653           rw_enter(&gp->g_glock, RW_READER);
654 }
655 
656 int
genfs_node_rdtrylock(struct vnode * vp)657 genfs_node_rdtrylock(struct vnode *vp)
658 {
659           struct genfs_node *gp = VTOG(vp);
660 
661           return rw_tryenter(&gp->g_glock, RW_READER);
662 }
663 
664 void
genfs_node_unlock(struct vnode * vp)665 genfs_node_unlock(struct vnode *vp)
666 {
667           struct genfs_node *gp = VTOG(vp);
668 
669           rw_exit(&gp->g_glock);
670 }
671 
672 int
genfs_node_wrlocked(struct vnode * vp)673 genfs_node_wrlocked(struct vnode *vp)
674 {
675           struct genfs_node *gp = VTOG(vp);
676 
677           return rw_write_held(&gp->g_glock);
678 }
679 
680 /*
681  * Common filesystem object access control check routine.  Accepts a
682  * vnode, cred, uid, gid, mode, acl, requested access mode.
683  * Returns 0 on success, or an errno on failure.
684  */
685 int
genfs_can_access(vnode_t * vp,kauth_cred_t cred,uid_t file_uid,gid_t file_gid,mode_t file_mode,struct acl * acl,accmode_t accmode)686 genfs_can_access(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, gid_t file_gid,
687     mode_t file_mode, struct acl *acl, accmode_t accmode)
688 {
689           accmode_t dac_granted;
690           int error;
691 
692           KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0);
693           KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
694 
695           /*
696            * Look for a normal, non-privileged way to access the file/directory
697            * as requested.  If it exists, go with that.
698            */
699 
700           dac_granted = 0;
701 
702           /* Check the owner. */
703           if (kauth_cred_geteuid(cred) == file_uid) {
704                     dac_granted |= VADMIN;
705                     if (file_mode & S_IXUSR)
706                               dac_granted |= VEXEC;
707                     if (file_mode & S_IRUSR)
708                               dac_granted |= VREAD;
709                     if (file_mode & S_IWUSR)
710                               dac_granted |= (VWRITE | VAPPEND);
711 
712                     goto privchk;
713           }
714 
715           /* Otherwise, check the groups (first match) */
716           /* Otherwise, check the groups. */
717           error = kauth_cred_groupmember(cred, file_gid);
718           if (error > 0)
719                     return error;
720           if (error == 0) {
721                     if (file_mode & S_IXGRP)
722                               dac_granted |= VEXEC;
723                     if (file_mode & S_IRGRP)
724                               dac_granted |= VREAD;
725                     if (file_mode & S_IWGRP)
726                               dac_granted |= (VWRITE | VAPPEND);
727 
728                     goto privchk;
729           }
730 
731           /* Otherwise, check everyone else. */
732           if (file_mode & S_IXOTH)
733                     dac_granted |= VEXEC;
734           if (file_mode & S_IROTH)
735                     dac_granted |= VREAD;
736           if (file_mode & S_IWOTH)
737                     dac_granted |= (VWRITE | VAPPEND);
738 
739 privchk:
740           if ((accmode & dac_granted) == accmode)
741                     return 0;
742 
743           return (accmode & VADMIN) ? EPERM : EACCES;
744 }
745 
746 /*
747  * Implement a version of genfs_can_access() that understands POSIX.1e ACL
748  * semantics;
749  * the access ACL has already been prepared for evaluation by the file system
750  * and is passed via 'uid', 'gid', and 'acl'.  Return 0 on success, else an
751  * errno value.
752  */
753 int
genfs_can_access_acl_posix1e(vnode_t * vp,kauth_cred_t cred,uid_t file_uid,gid_t file_gid,mode_t file_mode,struct acl * acl,accmode_t accmode)754 genfs_can_access_acl_posix1e(vnode_t *vp, kauth_cred_t cred, uid_t file_uid,
755     gid_t file_gid, mode_t file_mode, struct acl *acl, accmode_t accmode)
756 {
757           struct acl_entry *acl_other, *acl_mask;
758           accmode_t dac_granted;
759           accmode_t acl_mask_granted;
760           int group_matched, i;
761           int error;
762 
763           KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0);
764           KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
765 
766           /*
767            * The owner matches if the effective uid associated with the
768            * credential matches that of the ACL_USER_OBJ entry.  While we're
769            * doing the first scan, also cache the location of the ACL_MASK and
770            * ACL_OTHER entries, preventing some future iterations.
771            */
772           acl_mask = acl_other = NULL;
773           for (i = 0; i < acl->acl_cnt; i++) {
774                     struct acl_entry *ae = &acl->acl_entry[i];
775                     switch (ae->ae_tag) {
776                     case ACL_USER_OBJ:
777                               if (kauth_cred_geteuid(cred) != file_uid)
778                                         break;
779                               dac_granted = 0;
780                               dac_granted |= VADMIN;
781                               if (ae->ae_perm & ACL_EXECUTE)
782                                         dac_granted |= VEXEC;
783                               if (ae->ae_perm & ACL_READ)
784                                         dac_granted |= VREAD;
785                               if (ae->ae_perm & ACL_WRITE)
786                                         dac_granted |= (VWRITE | VAPPEND);
787                               goto out;
788 
789                     case ACL_MASK:
790                               acl_mask = ae;
791                               break;
792 
793                     case ACL_OTHER:
794                               acl_other = ae;
795                               break;
796 
797                     default:
798                               break;
799                     }
800           }
801 
802           /*
803            * An ACL_OTHER entry should always exist in a valid access ACL.  If
804            * it doesn't, then generate a serious failure.    For now, this means
805            * a debugging message and EPERM, but in the future should probably
806            * be a panic.
807            */
808           if (acl_other == NULL) {
809                     /*
810                      * XXX This should never happen
811                      */
812                     printf("%s: ACL_OTHER missing\n", __func__);
813                     return EPERM;
814           }
815 
816           /*
817            * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are
818            * masked by an ACL_MASK entry, if any.  As such, first identify the
819            * ACL_MASK field, then iterate through identifying potential user
820            * matches, then group matches.          If there is no ACL_MASK, assume that
821            * the mask allows all requests to succeed.
822            */
823           if (acl_mask != NULL) {
824                     acl_mask_granted = 0;
825                     if (acl_mask->ae_perm & ACL_EXECUTE)
826                               acl_mask_granted |= VEXEC;
827                     if (acl_mask->ae_perm & ACL_READ)
828                               acl_mask_granted |= VREAD;
829                     if (acl_mask->ae_perm & ACL_WRITE)
830                               acl_mask_granted |= (VWRITE | VAPPEND);
831           } else
832                     acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
833 
834           /*
835            * Check ACL_USER ACL entries.          There will either be one or no
836            * matches; if there is one, we accept or rejected based on the
837            * match; otherwise, we continue on to groups.
838            */
839           for (i = 0; i < acl->acl_cnt; i++) {
840                     struct acl_entry *ae = &acl->acl_entry[i];
841                     switch (ae->ae_tag) {
842                     case ACL_USER:
843                               if (kauth_cred_geteuid(cred) != ae->ae_id)
844                                         break;
845                               dac_granted = 0;
846                               if (ae->ae_perm & ACL_EXECUTE)
847                                         dac_granted |= VEXEC;
848                               if (ae->ae_perm & ACL_READ)
849                                         dac_granted |= VREAD;
850                               if (ae->ae_perm & ACL_WRITE)
851                                         dac_granted |= (VWRITE | VAPPEND);
852                               dac_granted &= acl_mask_granted;
853                               goto out;
854                     }
855           }
856 
857           /*
858            * Group match is best-match, not first-match, so find a "best"
859            * match.  Iterate across, testing each potential group match.        Make
860            * sure we keep track of whether we found a match or not, so that we
861            * know if we should try again with any available privilege, or if we
862            * should move on to ACL_OTHER.
863            */
864           group_matched = 0;
865           for (i = 0; i < acl->acl_cnt; i++) {
866                     struct acl_entry *ae = &acl->acl_entry[i];
867                     switch (ae->ae_tag) {
868                     case ACL_GROUP_OBJ:
869                               error = kauth_cred_groupmember(cred, file_gid);
870                               if (error > 0)
871                                         return error;
872                               if (error)
873                                         break;
874                               dac_granted = 0;
875                               if (ae->ae_perm & ACL_EXECUTE)
876                                         dac_granted |= VEXEC;
877                               if (ae->ae_perm & ACL_READ)
878                                         dac_granted |= VREAD;
879                               if (ae->ae_perm & ACL_WRITE)
880                                         dac_granted |= (VWRITE | VAPPEND);
881                               dac_granted  &= acl_mask_granted;
882 
883                               if ((accmode & dac_granted) == accmode)
884                                         return 0;
885 
886                               group_matched = 1;
887                               break;
888 
889                     case ACL_GROUP:
890                               error = kauth_cred_groupmember(cred, ae->ae_id);
891                               if (error > 0)
892                                         return error;
893                               if (error)
894                                         break;
895                               dac_granted = 0;
896                               if (ae->ae_perm & ACL_EXECUTE)
897                                         dac_granted |= VEXEC;
898                               if (ae->ae_perm & ACL_READ)
899                                         dac_granted |= VREAD;
900                               if (ae->ae_perm & ACL_WRITE)
901                                         dac_granted |= (VWRITE | VAPPEND);
902                               dac_granted  &= acl_mask_granted;
903 
904                               if ((accmode & dac_granted) == accmode)
905                                         return 0;
906 
907                               group_matched = 1;
908                               break;
909 
910                     default:
911                               break;
912                     }
913           }
914 
915           if (group_matched == 1) {
916                     /*
917                      * There was a match, but it did not grant rights via pure
918                      * DAC.    Try again, this time with privilege.
919                      */
920                     for (i = 0; i < acl->acl_cnt; i++) {
921                               struct acl_entry *ae = &acl->acl_entry[i];
922                               switch (ae->ae_tag) {
923                               case ACL_GROUP_OBJ:
924                                         error = kauth_cred_groupmember(cred, file_gid);
925                                         if (error > 0)
926                                                   return error;
927                                         if (error)
928                                                   break;
929                                         dac_granted = 0;
930                                         if (ae->ae_perm & ACL_EXECUTE)
931                                                   dac_granted |= VEXEC;
932                                         if (ae->ae_perm & ACL_READ)
933                                                   dac_granted |= VREAD;
934                                         if (ae->ae_perm & ACL_WRITE)
935                                                   dac_granted |= (VWRITE | VAPPEND);
936                                         dac_granted &= acl_mask_granted;
937                                         goto out;
938 
939                               case ACL_GROUP:
940                                         error = kauth_cred_groupmember(cred, ae->ae_id);
941                                         if (error > 0)
942                                                   return error;
943                                         if (error)
944                                                   break;
945                                         dac_granted = 0;
946                                         if (ae->ae_perm & ACL_EXECUTE)
947                                         dac_granted |= VEXEC;
948                                         if (ae->ae_perm & ACL_READ)
949                                                   dac_granted |= VREAD;
950                                         if (ae->ae_perm & ACL_WRITE)
951                                                   dac_granted |= (VWRITE | VAPPEND);
952                                         dac_granted &= acl_mask_granted;
953 
954                                         goto out;
955                               default:
956                                         break;
957                               }
958                     }
959                     /*
960                      * Even with privilege, group membership was not sufficient.
961                      * Return failure.
962                      */
963                     dac_granted = 0;
964                     goto out;
965           }
966 
967           /*
968            * Fall back on ACL_OTHER.  ACL_MASK is not applied to ACL_OTHER.
969            */
970           dac_granted = 0;
971           if (acl_other->ae_perm & ACL_EXECUTE)
972                     dac_granted |= VEXEC;
973           if (acl_other->ae_perm & ACL_READ)
974                     dac_granted |= VREAD;
975           if (acl_other->ae_perm & ACL_WRITE)
976                     dac_granted |= (VWRITE | VAPPEND);
977 
978 out:
979           if ((accmode & dac_granted) == accmode)
980                     return 0;
981           return (accmode & VADMIN) ? EPERM : EACCES;
982 }
983 
984 static struct {
985           accmode_t accmode;
986           int mask;
987 } accmode2mask[] = {
988           { VREAD, ACL_READ_DATA },
989           { VWRITE, ACL_WRITE_DATA },
990           { VAPPEND, ACL_APPEND_DATA },
991           { VEXEC, ACL_EXECUTE },
992           { VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS },
993           { VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS },
994           { VDELETE_CHILD, ACL_DELETE_CHILD },
995           { VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES },
996           { VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES },
997           { VDELETE, ACL_DELETE },
998           { VREAD_ACL, ACL_READ_ACL },
999           { VWRITE_ACL, ACL_WRITE_ACL },
1000           { VWRITE_OWNER, ACL_WRITE_OWNER },
1001           { VSYNCHRONIZE, ACL_SYNCHRONIZE },
1002           { 0, 0 },
1003 };
1004 
1005 static int
_access_mask_from_accmode(accmode_t accmode)1006 _access_mask_from_accmode(accmode_t accmode)
1007 {
1008           int access_mask = 0, i;
1009 
1010           for (i = 0; accmode2mask[i].accmode != 0; i++) {
1011                     if (accmode & accmode2mask[i].accmode)
1012                               access_mask |= accmode2mask[i].mask;
1013           }
1014 
1015           /*
1016            * VAPPEND is just a modifier for VWRITE; if the caller asked
1017            * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only.
1018            */
1019           if (access_mask & ACL_APPEND_DATA)
1020                     access_mask &= ~ACL_WRITE_DATA;
1021 
1022           return (access_mask);
1023 }
1024 
1025 /*
1026  * Return 0, iff access is allowed, 1 otherwise.
1027  */
1028 static int
_acl_denies(const struct acl * aclp,int access_mask,kauth_cred_t cred,int file_uid,int file_gid,int * denied_explicitly)1029 _acl_denies(const struct acl *aclp, int access_mask, kauth_cred_t cred,
1030     int file_uid, int file_gid, int *denied_explicitly)
1031 {
1032           int i, error;
1033           const struct acl_entry *ae;
1034 
1035           if (denied_explicitly != NULL)
1036                     *denied_explicitly = 0;
1037 
1038           KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES);
1039 
1040           for (i = 0; i < aclp->acl_cnt; i++) {
1041                     ae = &(aclp->acl_entry[i]);
1042 
1043                     if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
1044                         ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
1045                               continue;
1046                     if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY)
1047                               continue;
1048                     switch (ae->ae_tag) {
1049                     case ACL_USER_OBJ:
1050                               if (kauth_cred_geteuid(cred) != file_uid)
1051                                         continue;
1052                               break;
1053                     case ACL_USER:
1054                               if (kauth_cred_geteuid(cred) != ae->ae_id)
1055                                         continue;
1056                               break;
1057                     case ACL_GROUP_OBJ:
1058                               error = kauth_cred_groupmember(cred, file_gid);
1059                               if (error > 0)
1060                                         return error;
1061                               if (error != 0)
1062                                         continue;
1063                               break;
1064                     case ACL_GROUP:
1065                               error = kauth_cred_groupmember(cred, ae->ae_id);
1066                               if (error > 0)
1067                                         return error;
1068                               if (error != 0)
1069                                         continue;
1070                               break;
1071                     default:
1072                               KASSERT(ae->ae_tag == ACL_EVERYONE);
1073                     }
1074 
1075                     if (ae->ae_entry_type == ACL_ENTRY_TYPE_DENY) {
1076                               if (ae->ae_perm & access_mask) {
1077                                         if (denied_explicitly != NULL)
1078                                                   *denied_explicitly = 1;
1079                                         return (1);
1080                               }
1081                     }
1082 
1083                     access_mask &= ~(ae->ae_perm);
1084                     if (access_mask == 0)
1085                               return (0);
1086           }
1087 
1088           if (access_mask == 0)
1089                     return (0);
1090 
1091           return (1);
1092 }
1093 
1094 int
genfs_can_access_acl_nfs4(vnode_t * vp,kauth_cred_t cred,uid_t file_uid,gid_t file_gid,mode_t file_mode,struct acl * aclp,accmode_t accmode)1095 genfs_can_access_acl_nfs4(vnode_t *vp, kauth_cred_t cred, uid_t file_uid,
1096     gid_t file_gid, mode_t file_mode, struct acl *aclp, accmode_t accmode)
1097 {
1098           int denied, explicitly_denied, access_mask, is_directory,
1099               must_be_owner = 0;
1100           file_mode = 0;
1101 
1102           KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND |
1103               VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS |
1104               VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE |
1105               VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0);
1106           KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
1107 
1108           if (accmode & VADMIN)
1109                     must_be_owner = 1;
1110 
1111           /*
1112            * Ignore VSYNCHRONIZE permission.
1113            */
1114           accmode &= ~VSYNCHRONIZE;
1115 
1116           access_mask = _access_mask_from_accmode(accmode);
1117 
1118           if (vp && vp->v_type == VDIR)
1119                     is_directory = 1;
1120           else
1121                     is_directory = 0;
1122 
1123           /*
1124            * File owner is always allowed to read and write the ACL
1125            * and basic attributes.  This is to prevent a situation
1126            * where user would change ACL in a way that prevents him
1127            * from undoing the change.
1128            */
1129           if (kauth_cred_geteuid(cred) == file_uid)
1130                     access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL |
1131                         ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES);
1132 
1133           /*
1134            * Ignore append permission for regular files; use write
1135            * permission instead.
1136            */
1137           if (!is_directory && (access_mask & ACL_APPEND_DATA)) {
1138                     access_mask &= ~ACL_APPEND_DATA;
1139                     access_mask |= ACL_WRITE_DATA;
1140           }
1141 
1142           denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid,
1143               &explicitly_denied);
1144 
1145           if (must_be_owner) {
1146                     if (kauth_cred_geteuid(cred) != file_uid)
1147                               denied = EPERM;
1148           }
1149 
1150           /*
1151            * For VEXEC, ensure that at least one execute bit is set for
1152            * non-directories. We have to check the mode here to stay
1153            * consistent with execve(2). See the test in
1154            * exec_check_permissions().
1155            */
1156           __acl_nfs4_sync_mode_from_acl(&file_mode, aclp);
1157           if (!denied && !is_directory && (accmode & VEXEC) &&
1158               (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
1159                     denied = EACCES;
1160 
1161           if (!denied)
1162                     return (0);
1163 
1164           /*
1165            * Access failed.  Iff it was not denied explicitly and
1166            * VEXPLICIT_DENY flag was specified, allow access.
1167            */
1168           if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0)
1169                     return (0);
1170 
1171           accmode &= ~VEXPLICIT_DENY;
1172 
1173           if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE))
1174                     denied = EPERM;
1175           else
1176                     denied = EACCES;
1177 
1178           return (denied);
1179 }
1180 
1181 /*
1182  * Common routine to check if chmod() is allowed.
1183  *
1184  * Policy:
1185  *   - You must own the file, and
1186  *     - You must not set the "sticky" bit (meaningless, see chmod(2))
1187  *     - You must be a member of the group if you're trying to set the
1188  *         SGIDf bit
1189  *
1190  * vp - vnode of the file-system object
1191  * cred - credentials of the invoker
1192  * cur_uid, cur_gid - current uid/gid of the file-system object
1193  * new_mode - new mode for the file-system object
1194  *
1195  * Returns 0 if the change is allowed, or an error value otherwise.
1196  */
1197 int
genfs_can_chmod(vnode_t * vp,kauth_cred_t cred,uid_t cur_uid,gid_t cur_gid,mode_t new_mode)1198 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
1199     gid_t cur_gid, mode_t new_mode)
1200 {
1201           int error;
1202 
1203           /*
1204            * To modify the permissions on a file, must possess VADMIN
1205            * for that file.
1206            */
1207           if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred)) != 0)
1208                     return (error);
1209 
1210           /*
1211            * Unprivileged users can't set the sticky bit on files.
1212            */
1213           if ((vp->v_type != VDIR) && (new_mode & S_ISTXT))
1214                     return (EFTYPE);
1215 
1216           /*
1217            * If the invoker is trying to set the SGID bit on the file,
1218            * check group membership.
1219            */
1220           if (new_mode & S_ISGID) {
1221                     int ismember;
1222 
1223                     error = kauth_cred_ismember_gid(cred, cur_gid,
1224                         &ismember);
1225                     if (error || !ismember)
1226                               return (EPERM);
1227           }
1228 
1229           /*
1230            * Deny setting setuid if we are not the file owner.
1231            */
1232           if ((new_mode & S_ISUID) && cur_uid != kauth_cred_geteuid(cred))
1233                     return (EPERM);
1234 
1235           return (0);
1236 }
1237 
1238 /*
1239  * Common routine to check if chown() is allowed.
1240  *
1241  * Policy:
1242  *   - You must own the file, and
1243  *     - You must not try to change ownership, and
1244  *     - You must be member of the new group
1245  *
1246  * vp - vnode
1247  * cred - credentials of the invoker
1248  * cur_uid, cur_gid - current uid/gid of the file-system object
1249  * new_uid, new_gid - target uid/gid of the file-system object
1250  *
1251  * Returns 0 if the change is allowed, or an error value otherwise.
1252  */
1253 int
genfs_can_chown(vnode_t * vp,kauth_cred_t cred,uid_t cur_uid,gid_t cur_gid,uid_t new_uid,gid_t new_gid)1254 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
1255     gid_t cur_gid, uid_t new_uid, gid_t new_gid)
1256 {
1257           int error, ismember;
1258 
1259           /*
1260            * To modify the ownership of a file, must possess VADMIN for that
1261            * file.
1262            */
1263           if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred)) != 0)
1264                     return (error);
1265 
1266           /*
1267            * You can only change ownership of a file if:
1268            * You own the file and...
1269            */
1270           if (kauth_cred_geteuid(cred) == cur_uid) {
1271                     /*
1272                      * You don't try to change ownership, and...
1273                      */
1274                     if (new_uid != cur_uid)
1275                               return (EPERM);
1276 
1277                     /*
1278                      * You don't try to change group (no-op), or...
1279                      */
1280                     if (new_gid == cur_gid)
1281                               return (0);
1282 
1283                     /*
1284                      * Your effective gid is the new gid, or...
1285                      */
1286                     if (kauth_cred_getegid(cred) == new_gid)
1287                               return (0);
1288 
1289                     /*
1290                      * The new gid is one you're a member of.
1291                      */
1292                     ismember = 0;
1293                     error = kauth_cred_ismember_gid(cred, new_gid,
1294                         &ismember);
1295                     if (!error && ismember)
1296                               return (0);
1297           }
1298 
1299           return (EPERM);
1300 }
1301 
1302 int
genfs_can_chtimes(vnode_t * vp,kauth_cred_t cred,uid_t owner_uid,u_int vaflags)1303 genfs_can_chtimes(vnode_t *vp, kauth_cred_t cred, uid_t owner_uid,
1304     u_int vaflags)
1305 {
1306           int error;
1307           /*
1308            * Grant permission if the caller is the owner of the file, or
1309            * the super-user, or has ACL_WRITE_ATTRIBUTES permission on
1310            * on the file.      If the time pointer is null, then write
1311            * permission on the file is also sufficient.
1312            *
1313            * From NFSv4.1, draft 21, 6.2.1.3.1, Discussion of Mask Attributes:
1314            * A user having ACL_WRITE_DATA or ACL_WRITE_ATTRIBUTES
1315            * will be allowed to set the times [..] to the current
1316            * server time.
1317            */
1318           error = VOP_ACCESSX(vp, VWRITE_ATTRIBUTES, cred);
1319           if (error != 0 && (vaflags & VA_UTIMES_NULL) != 0)
1320                     error = VOP_ACCESS(vp, VWRITE, cred);
1321 
1322           if (error)
1323                     return (vaflags & VA_UTIMES_NULL) == 0 ? EPERM : EACCES;
1324 
1325           return 0;
1326 }
1327 
1328 /*
1329  * Common routine to check if chflags() is allowed.
1330  *
1331  * Policy:
1332  *   - You must own the file, and
1333  *   - You must not change system flags, and
1334  *   - You must not change flags on character/block devices.
1335  *
1336  * vp - vnode
1337  * cred - credentials of the invoker
1338  * owner_uid - uid of the file-system object
1339  * changing_sysflags - true if the invoker wants to change system flags
1340  */
1341 int
genfs_can_chflags(vnode_t * vp,kauth_cred_t cred,uid_t owner_uid,bool changing_sysflags)1342 genfs_can_chflags(vnode_t *vp, kauth_cred_t cred,
1343      uid_t owner_uid, bool changing_sysflags)
1344 {
1345 
1346           /* The user must own the file. */
1347           if (kauth_cred_geteuid(cred) != owner_uid) {
1348                     return EPERM;
1349           }
1350 
1351           if (changing_sysflags) {
1352                     return EPERM;
1353           }
1354 
1355           /*
1356            * Unprivileged users cannot change the flags on devices, even if they
1357            * own them.
1358            */
1359           if (vp->v_type == VCHR || vp->v_type == VBLK) {
1360                     return EPERM;
1361           }
1362 
1363           return 0;
1364 }
1365 
1366 /*
1367  * Common "sticky" policy.
1368  *
1369  * When a directory is "sticky" (as determined by the caller), this
1370  * function may help implementing the following policy:
1371  * - Renaming a file in it is only possible if the user owns the directory
1372  *   or the file being renamed.
1373  * - Deleting a file from it is only possible if the user owns the
1374  *   directory or the file being deleted.
1375  */
1376 int
genfs_can_sticky(vnode_t * vp,kauth_cred_t cred,uid_t dir_uid,uid_t file_uid)1377 genfs_can_sticky(vnode_t *vp, kauth_cred_t cred, uid_t dir_uid, uid_t file_uid)
1378 {
1379           if (kauth_cred_geteuid(cred) != dir_uid &&
1380               kauth_cred_geteuid(cred) != file_uid)
1381                     return EPERM;
1382 
1383           return 0;
1384 }
1385 
1386 int
genfs_can_extattr(vnode_t * vp,kauth_cred_t cred,accmode_t accmode,int attrnamespace)1387 genfs_can_extattr(vnode_t *vp, kauth_cred_t cred, accmode_t accmode,
1388     int attrnamespace)
1389 {
1390           /*
1391            * Kernel-invoked always succeeds.
1392            */
1393           if (cred == NOCRED)
1394                     return 0;
1395 
1396           switch (attrnamespace) {
1397           case EXTATTR_NAMESPACE_SYSTEM:
1398                     return kauth_authorize_system(cred, KAUTH_SYSTEM_FS_EXTATTR,
1399                         0, vp->v_mount, NULL, NULL);
1400           case EXTATTR_NAMESPACE_USER:
1401                     return VOP_ACCESS(vp, accmode, cred);
1402           default:
1403                     return EPERM;
1404           }
1405 }
1406 
1407 int
genfs_access(void * v)1408 genfs_access(void *v)
1409 {
1410           struct vop_access_args *ap = v;
1411 
1412           KASSERT((ap->a_accmode & ~(VEXEC | VWRITE | VREAD | VADMIN |
1413               VAPPEND)) == 0);
1414 
1415           return VOP_ACCESSX(ap->a_vp, ap->a_accmode, ap->a_cred);
1416 }
1417 
1418 int
genfs_accessx(void * v)1419 genfs_accessx(void *v)
1420 {
1421           struct vop_accessx_args *ap = v;
1422           int error;
1423           accmode_t accmode = ap->a_accmode;
1424           error = vfs_unixify_accmode(&accmode);
1425           if (error != 0)
1426                     return error;
1427 
1428           if (accmode == 0)
1429                     return 0;
1430 
1431           return VOP_ACCESS(ap->a_vp, accmode, ap->a_cred);
1432 }
1433 
1434 /*
1435  * genfs_pathconf:
1436  *
1437  * Standard implementation of POSIX pathconf, to get information about limits
1438  * for a filesystem.
1439  * Override per filesystem for the case where the filesystem has smaller
1440  * limits.
1441  */
1442 int
genfs_pathconf(void * v)1443 genfs_pathconf(void *v)
1444 {
1445           struct vop_pathconf_args *ap = v;
1446 
1447           switch (ap->a_name) {
1448           case _PC_PATH_MAX:
1449                     *ap->a_retval = PATH_MAX;
1450                     return 0;
1451           case _PC_ACL_EXTENDED:
1452           case _PC_ACL_NFS4:
1453                     *ap->a_retval = 0;
1454                     return 0;
1455           default:
1456                     return EINVAL;
1457           }
1458 }
1459