1 /* $NetBSD: umap_vnops.c,v 1.62 2021/10/20 03:08:18 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * the UCLA Ficus project. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)umap_vnops.c 8.6 (Berkeley) 5/22/95 35 */ 36 37 /* 38 * Umap Layer 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: umap_vnops.c,v 1.62 2021/10/20 03:08:18 thorpej Exp $"); 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/time.h> 47 #include <sys/vnode.h> 48 #include <sys/mount.h> 49 #include <sys/namei.h> 50 #include <sys/buf.h> 51 #include <sys/kauth.h> 52 53 #include <miscfs/umapfs/umap.h> 54 #include <miscfs/genfs/genfs.h> 55 #include <miscfs/genfs/layer_extern.h> 56 57 /* 58 * Note: If the LAYERFS_MBYPASSDEBUG flag is set, it is possible 59 * that the debug printing will bomb out, because kauth routines 60 * do not handle NOCRED or FSCRED like other credentials and end 61 * up dereferencing an inappropriate pointer. 62 * 63 * That should be fixed in kauth rather than here. 64 */ 65 66 int umap_lookup(void *); 67 int umap_getattr(void *); 68 int umap_print(void *); 69 int umap_rename(void *); 70 71 /* 72 * Global vfs data structures 73 */ 74 /* 75 * XXX - strategy, bwrite are hand coded currently. They should 76 * go away with a merged buffer/block cache. 77 * 78 */ 79 int (**umap_vnodeop_p)(void *); 80 const struct vnodeopv_entry_desc umap_vnodeop_entries[] = { 81 { &vop_default_desc, umap_bypass }, 82 83 { &vop_lookup_desc, umap_lookup }, 84 { &vop_getattr_desc, umap_getattr }, 85 { &vop_print_desc, umap_print }, 86 { &vop_rename_desc, umap_rename }, 87 88 { &vop_fsync_desc, layer_fsync }, 89 { &vop_inactive_desc, layer_inactive }, 90 { &vop_reclaim_desc, layer_reclaim }, 91 { &vop_open_desc, layer_open }, 92 { &vop_close_desc, layer_close }, 93 { &vop_setattr_desc, layer_setattr }, 94 { &vop_access_desc, layer_access }, 95 { &vop_accessx_desc, genfs_accessx }, 96 { &vop_remove_desc, layer_remove }, 97 { &vop_revoke_desc, layer_revoke }, 98 { &vop_rmdir_desc, layer_rmdir }, 99 100 { &vop_bmap_desc, layer_bmap }, 101 { &vop_getpages_desc, layer_getpages }, 102 { &vop_putpages_desc, layer_putpages }, 103 104 { NULL, NULL } 105 }; 106 const struct vnodeopv_desc umapfs_vnodeop_opv_desc = 107 { &umap_vnodeop_p, umap_vnodeop_entries }; 108 109 /* 110 * This is the 08-June-1999 bypass routine. 111 * See layer_vnops.c:layer_bypass for more details. 112 */ 113 int 114 umap_bypass(void *v) 115 { 116 struct vop_generic_args /* { 117 struct vnodeop_desc *a_desc; 118 <other random data follows, presumably> 119 } */ *ap = v; 120 int (**our_vnodeop_p)(void *); 121 kauth_cred_t *credpp = NULL, credp = 0; 122 kauth_cred_t savecredp = 0, savecompcredp = 0; 123 kauth_cred_t compcredp = 0; 124 struct vnode **this_vp_p; 125 int error; 126 struct vnode *old_vps[VDESC_MAX_VPS], *vp0; 127 struct vnode **vps_p[VDESC_MAX_VPS]; 128 struct vnode ***vppp; 129 struct vnodeop_desc *descp = ap->a_desc; 130 int reles, i, flags; 131 struct componentname **compnamepp = 0; 132 133 #ifdef DIAGNOSTIC 134 /* 135 * We require at least one vp. 136 */ 137 if (descp->vdesc_vp_offsets == NULL || 138 descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) 139 panic("%s: no vp's in map.\n", __func__); 140 #endif 141 142 vps_p[0] = 143 VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap); 144 vp0 = *vps_p[0]; 145 flags = MOUNTTOUMAPMOUNT(vp0->v_mount)->umapm_flags; 146 our_vnodeop_p = vp0->v_op; 147 148 if (flags & LAYERFS_MBYPASSDEBUG) 149 printf("%s: %s\n", __func__, descp->vdesc_name); 150 151 /* 152 * Map the vnodes going in. 153 * Later, we'll invoke the operation based on 154 * the first mapped vnode's operation vector. 155 */ 156 reles = descp->vdesc_flags; 157 for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 158 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 159 break; /* bail out at end of list */ 160 vps_p[i] = this_vp_p = 161 VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], 162 ap); 163 /* 164 * We're not guaranteed that any but the first vnode 165 * are of our type. Check for and don't map any 166 * that aren't. (We must always map first vp or vclean fails.) 167 */ 168 if (i && (*this_vp_p == NULL || 169 (*this_vp_p)->v_op != our_vnodeop_p)) { 170 old_vps[i] = NULL; 171 } else { 172 old_vps[i] = *this_vp_p; 173 *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p); 174 /* 175 * XXX - Several operations have the side effect 176 * of vrele'ing their vp's. We must account for 177 * that. (This should go away in the future.) 178 */ 179 if (reles & VDESC_VP0_WILLRELE) 180 vref(*this_vp_p); 181 } 182 183 } 184 185 /* 186 * Fix the credentials. (That's the purpose of this layer.) 187 */ 188 189 if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { 190 191 credpp = VOPARG_OFFSETTO(kauth_cred_t*, 192 descp->vdesc_cred_offset, ap); 193 194 /* Save old values */ 195 196 savecredp = *credpp; 197 if (savecredp != NOCRED && savecredp != FSCRED) 198 *credpp = kauth_cred_dup(savecredp); 199 credp = *credpp; 200 201 if ((flags & LAYERFS_MBYPASSDEBUG) && 202 kauth_cred_geteuid(credp) != 0) 203 printf("umap_bypass: user was %d, group %d\n", 204 kauth_cred_geteuid(credp), kauth_cred_getegid(credp)); 205 206 /* Map all ids in the credential structure. */ 207 208 umap_mapids(vp0->v_mount, credp); 209 210 if ((flags & LAYERFS_MBYPASSDEBUG) && 211 kauth_cred_geteuid(credp) != 0) 212 printf("umap_bypass: user now %d, group %d\n", 213 kauth_cred_geteuid(credp), kauth_cred_getegid(credp)); 214 } 215 216 /* BSD often keeps a credential in the componentname structure 217 * for speed. If there is one, it better get mapped, too. 218 */ 219 220 if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { 221 222 compnamepp = VOPARG_OFFSETTO(struct componentname**, 223 descp->vdesc_componentname_offset, ap); 224 225 savecompcredp = (*compnamepp)->cn_cred; 226 if (savecompcredp != NOCRED && savecompcredp != FSCRED) 227 (*compnamepp)->cn_cred = kauth_cred_dup(savecompcredp); 228 compcredp = (*compnamepp)->cn_cred; 229 230 if ((flags & LAYERFS_MBYPASSDEBUG) && 231 kauth_cred_geteuid(compcredp) != 0) 232 printf("umap_bypass: component credit user was %d, group %d\n", 233 kauth_cred_geteuid(compcredp), kauth_cred_getegid(compcredp)); 234 235 /* Map all ids in the credential structure. */ 236 237 umap_mapids(vp0->v_mount, compcredp); 238 239 if ((flags & LAYERFS_MBYPASSDEBUG) && 240 kauth_cred_geteuid(compcredp) != 0) 241 printf("umap_bypass: component credit user now %d, group %d\n", 242 kauth_cred_geteuid(compcredp), kauth_cred_getegid(compcredp)); 243 } 244 245 /* 246 * Call the operation on the lower layer 247 * with the modified argument structure. 248 */ 249 error = VCALL(*vps_p[0], descp->vdesc_offset, ap); 250 251 /* 252 * Maintain the illusion of call-by-value 253 * by restoring vnodes in the argument structure 254 * to their original value. 255 */ 256 reles = descp->vdesc_flags; 257 for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 258 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 259 break; /* bail out at end of list */ 260 if (old_vps[i]) { 261 *(vps_p[i]) = old_vps[i]; 262 if (reles & VDESC_VP0_WILLRELE) 263 vrele(*(vps_p[i])); 264 } 265 } 266 267 /* 268 * Map the possible out-going vpp 269 * (Assumes that the lower layer always returns 270 * a VREF'ed vpp unless it gets an error.) 271 */ 272 if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && !error) { 273 vppp = VOPARG_OFFSETTO(struct vnode***, 274 descp->vdesc_vpp_offset, ap); 275 /* 276 * Only vop_lookup, vop_create, vop_makedir, vop_mknod 277 * and vop_symlink return vpp's. vop_lookup doesn't call bypass 278 * as a lookup on "." would generate a locking error. 279 * So all the calls which get us here have a unlocked vpp. :-) 280 */ 281 error = layer_node_create(old_vps[0]->v_mount, **vppp, *vppp); 282 if (error) { 283 vrele(**vppp); 284 **vppp = NULL; 285 } 286 } 287 288 /* 289 * Free duplicate cred structure and restore old one. 290 */ 291 if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { 292 if ((flags & LAYERFS_MBYPASSDEBUG) && credp && 293 kauth_cred_geteuid(credp) != 0) 294 printf("umap_bypass: returning-user was %d\n", 295 kauth_cred_geteuid(credp)); 296 297 if (savecredp != NOCRED && savecredp != FSCRED && credpp) { 298 kauth_cred_free(credp); 299 *credpp = savecredp; 300 if ((flags & LAYERFS_MBYPASSDEBUG) && credpp && 301 kauth_cred_geteuid(*credpp) != 0) 302 printf("umap_bypass: returning-user now %d\n\n", 303 kauth_cred_geteuid(savecredp)); 304 } 305 } 306 307 if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { 308 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp && 309 kauth_cred_geteuid(compcredp) != 0) 310 printf("umap_bypass: returning-component-user was %d\n", 311 kauth_cred_geteuid(compcredp)); 312 313 if (savecompcredp != NOCRED && savecompcredp != FSCRED) { 314 kauth_cred_free(compcredp); 315 (*compnamepp)->cn_cred = savecompcredp; 316 if ((flags & LAYERFS_MBYPASSDEBUG) && savecompcredp && 317 kauth_cred_geteuid(savecompcredp) != 0) 318 printf("umap_bypass: returning-component-user now %d\n", 319 kauth_cred_geteuid(savecompcredp)); 320 } 321 } 322 323 return (error); 324 } 325 326 /* 327 * This is based on the 08-June-1999 bypass routine. 328 * See layer_vnops.c:layer_bypass for more details. 329 */ 330 int 331 umap_lookup(void *v) 332 { 333 struct vop_lookup_v2_args /* { 334 struct vnodeop_desc *a_desc; 335 struct vnode * a_dvp; 336 struct vnode ** a_vpp; 337 struct componentname * a_cnp; 338 } */ *ap = v; 339 struct componentname *cnp = ap->a_cnp; 340 kauth_cred_t savecompcredp = NULL; 341 kauth_cred_t compcredp = NULL; 342 struct vnode *dvp, *vp, *ldvp; 343 struct mount *mp; 344 int error; 345 int flags, cnf = cnp->cn_flags; 346 347 dvp = ap->a_dvp; 348 mp = dvp->v_mount; 349 350 if ((cnf & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 351 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 352 return (EROFS); 353 354 flags = MOUNTTOUMAPMOUNT(mp)->umapm_flags; 355 ldvp = UMAPVPTOLOWERVP(dvp); 356 357 if (flags & LAYERFS_MBYPASSDEBUG) 358 printf("umap_lookup\n"); 359 360 /* 361 * Fix the credentials. (That's the purpose of this layer.) 362 * 363 * BSD often keeps a credential in the componentname structure 364 * for speed. If there is one, it better get mapped, too. 365 */ 366 367 if ((savecompcredp = cnp->cn_cred)) { 368 compcredp = kauth_cred_dup(savecompcredp); 369 cnp->cn_cred = compcredp; 370 371 if ((flags & LAYERFS_MBYPASSDEBUG) && 372 kauth_cred_geteuid(compcredp) != 0) 373 printf("umap_lookup: component credit user was %d, group %d\n", 374 kauth_cred_geteuid(compcredp), kauth_cred_getegid(compcredp)); 375 376 /* Map all ids in the credential structure. */ 377 umap_mapids(mp, compcredp); 378 } 379 380 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp && 381 kauth_cred_geteuid(compcredp) != 0) 382 printf("umap_lookup: component credit user now %d, group %d\n", 383 kauth_cred_geteuid(compcredp), kauth_cred_getegid(compcredp)); 384 385 ap->a_dvp = ldvp; 386 error = VCALL(ldvp, ap->a_desc->vdesc_offset, ap); 387 vp = *ap->a_vpp; 388 *ap->a_vpp = NULL; 389 390 if (error == EJUSTRETURN && (cnf & ISLASTCN) && 391 (dvp->v_mount->mnt_flag & MNT_RDONLY) && 392 (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) 393 error = EROFS; 394 395 /* Do locking fixup as appropriate. See layer_lookup() for info */ 396 if (ldvp == vp) { 397 *ap->a_vpp = dvp; 398 vref(dvp); 399 vrele(vp); 400 } else if (vp != NULL) { 401 error = layer_node_create(mp, vp, ap->a_vpp); 402 if (error) { 403 vrele(vp); 404 } 405 } 406 407 /* 408 * Free duplicate cred structure and restore old one. 409 */ 410 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp && 411 kauth_cred_geteuid(compcredp) != 0) 412 printf("umap_lookup: returning-component-user was %d\n", 413 kauth_cred_geteuid(compcredp)); 414 415 if (savecompcredp != NOCRED && savecompcredp != FSCRED) { 416 if (compcredp) 417 kauth_cred_free(compcredp); 418 cnp->cn_cred = savecompcredp; 419 if ((flags & LAYERFS_MBYPASSDEBUG) && savecompcredp && 420 kauth_cred_geteuid(savecompcredp) != 0) 421 printf("umap_lookup: returning-component-user now %d\n", 422 kauth_cred_geteuid(savecompcredp)); 423 } 424 425 return (error); 426 } 427 428 /* 429 * We handle getattr to change the fsid. 430 */ 431 int 432 umap_getattr(void *v) 433 { 434 struct vop_getattr_args /* { 435 struct vnode *a_vp; 436 struct vattr *a_vap; 437 kauth_cred_t a_cred; 438 struct lwp *a_l; 439 } */ *ap = v; 440 uid_t uid; 441 gid_t gid; 442 int error, tmpid, nentries, gnentries, flags; 443 u_long (*mapdata)[2]; 444 u_long (*gmapdata)[2]; 445 struct vnode **vp1p; 446 const struct vnodeop_desc *descp = ap->a_desc; 447 448 if ((error = umap_bypass(ap)) != 0) 449 return (error); 450 /* Requires that arguments be restored. */ 451 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 452 453 flags = MOUNTTOUMAPMOUNT(ap->a_vp->v_mount)->umapm_flags; 454 /* 455 * Umap needs to map the uid and gid returned by a stat 456 * into the proper values for this site. This involves 457 * finding the returned uid in the mapping information, 458 * translating it into the uid on the other end, 459 * and filling in the proper field in the vattr 460 * structure pointed to by ap->a_vap. The group 461 * is easier, since currently all groups will be 462 * translate to the NULLGROUP. 463 */ 464 465 /* Find entry in map */ 466 467 uid = ap->a_vap->va_uid; 468 gid = ap->a_vap->va_gid; 469 if ((flags & LAYERFS_MBYPASSDEBUG)) 470 printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid, 471 gid); 472 473 vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap); 474 nentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries; 475 mapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata); 476 gnentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries; 477 gmapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata); 478 479 /* Reverse map the uid for the vnode. Since it's a reverse 480 map, we can't use umap_mapids() to do it. */ 481 482 tmpid = umap_reverse_findid(uid, mapdata, nentries); 483 484 if (tmpid != -1) { 485 ap->a_vap->va_uid = (uid_t) tmpid; 486 if ((flags & LAYERFS_MBYPASSDEBUG)) 487 printf("umap_getattr: original uid = %d\n", uid); 488 } else 489 ap->a_vap->va_uid = (uid_t) NOBODY; 490 491 /* Reverse map the gid for the vnode. */ 492 493 tmpid = umap_reverse_findid(gid, gmapdata, gnentries); 494 495 if (tmpid != -1) { 496 ap->a_vap->va_gid = (gid_t) tmpid; 497 if ((flags & LAYERFS_MBYPASSDEBUG)) 498 printf("umap_getattr: original gid = %d\n", gid); 499 } else 500 ap->a_vap->va_gid = (gid_t) NULLGROUP; 501 502 return (0); 503 } 504 505 int 506 umap_print(void *v) 507 { 508 struct vop_print_args /* { 509 struct vnode *a_vp; 510 } */ *ap = v; 511 struct vnode *vp = ap->a_vp; 512 printf("\ttag VT_UMAPFS, vp=%p, lowervp=%p\n", vp, 513 UMAPVPTOLOWERVP(vp)); 514 return (0); 515 } 516 517 int 518 umap_rename(void *v) 519 { 520 struct vop_rename_args /* { 521 struct vnode *a_fdvp; 522 struct vnode *a_fvp; 523 struct componentname *a_fcnp; 524 struct vnode *a_tdvp; 525 struct vnode *a_tvp; 526 struct componentname *a_tcnp; 527 } */ *ap = v; 528 int error, flags; 529 struct componentname *compnamep; 530 kauth_cred_t compcredp, savecompcredp; 531 struct vnode *vp; 532 struct vnode *tvp; 533 534 /* 535 * Rename is irregular, having two componentname structures. 536 * We need to map the cre in the second structure, 537 * and then bypass takes care of the rest. 538 */ 539 540 vp = ap->a_fdvp; 541 flags = MOUNTTOUMAPMOUNT(vp->v_mount)->umapm_flags; 542 compnamep = ap->a_tcnp; 543 compcredp = compnamep->cn_cred; 544 545 savecompcredp = compcredp; 546 compcredp = compnamep->cn_cred = kauth_cred_dup(savecompcredp); 547 548 if ((flags & LAYERFS_MBYPASSDEBUG) && 549 kauth_cred_geteuid(compcredp) != 0) 550 printf("umap_rename: rename component credit user was %d, group %d\n", 551 kauth_cred_geteuid(compcredp), kauth_cred_getegid(compcredp)); 552 553 /* Map all ids in the credential structure. */ 554 555 umap_mapids(vp->v_mount, compcredp); 556 557 if ((flags & LAYERFS_MBYPASSDEBUG) && 558 kauth_cred_geteuid(compcredp) != 0) 559 printf("umap_rename: rename component credit user now %d, group %d\n", 560 kauth_cred_geteuid(compcredp), kauth_cred_getegid(compcredp)); 561 562 tvp = ap->a_tvp; 563 if (tvp) { 564 if (tvp->v_mount != vp->v_mount) 565 tvp = NULL; 566 else 567 vref(tvp); 568 } 569 error = umap_bypass(ap); 570 if (tvp) { 571 if (error == 0) 572 VTOLAYER(tvp)->layer_flags |= LAYERFS_REMOVED; 573 vrele(tvp); 574 } 575 576 /* Restore the additional mapped componentname cred structure. */ 577 578 kauth_cred_free(compcredp); 579 compnamep->cn_cred = savecompcredp; 580 581 return error; 582 } 583