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