1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/errno.h> 27 #include <sys/vfs.h> 28 #include <sys/vfs_opreg.h> 29 #include <sys/vnode.h> 30 #include <sys/uio.h> 31 #include <sys/pathname.h> 32 #include <sys/kmem.h> 33 #include <sys/cred.h> 34 #include <sys/statvfs.h> 35 #include <sys/fs/lofs_info.h> 36 #include <sys/fs/lofs_node.h> 37 #include <sys/mount.h> 38 #include <sys/mntent.h> 39 #include <sys/mkdev.h> 40 #include <sys/priv.h> 41 #include <sys/sysmacros.h> 42 #include <sys/systm.h> 43 #include <sys/cmn_err.h> 44 #include <sys/policy.h> 45 #include <sys/tsol/label.h> 46 #include "fs/fs_subr.h" 47 48 /* 49 * This is the loadable module wrapper. 50 */ 51 #include <sys/modctl.h> 52 53 static mntopts_t lofs_mntopts; 54 55 static int lofsinit(int, char *); 56 57 static vfsdef_t vfw = { 58 VFSDEF_VERSION, 59 "lofs", 60 lofsinit, 61 VSW_HASPROTO|VSW_STATS|VSW_ZMOUNT, 62 &lofs_mntopts 63 }; 64 65 /* 66 * LOFS mount options table 67 */ 68 static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 69 static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 70 static char *sub_cancel[] = { MNTOPT_LOFS_NOSUB, NULL }; 71 static char *nosub_cancel[] = { MNTOPT_LOFS_SUB, NULL }; 72 73 static mntopt_t mntopts[] = { 74 /* 75 * option name cancel option default arg flags 76 * private data 77 */ 78 { MNTOPT_XATTR, xattr_cancel, NULL, 0, 79 (void *)0 }, 80 { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 81 (void *)0 }, 82 { MNTOPT_LOFS_SUB, sub_cancel, NULL, 0, 83 (void *)0 }, 84 { MNTOPT_LOFS_NOSUB, nosub_cancel, NULL, 0, 85 (void *)0 }, 86 }; 87 88 static mntopts_t lofs_mntopts = { 89 sizeof (mntopts) / sizeof (mntopt_t), 90 mntopts 91 }; 92 93 /* 94 * Module linkage information for the kernel. 95 */ 96 97 static struct modlfs modlfs = { 98 &mod_fsops, "filesystem for lofs", &vfw 99 }; 100 101 static struct modlinkage modlinkage = { 102 MODREV_1, { (void *)&modlfs, NULL } 103 }; 104 105 /* 106 * This is the module initialization routine. 107 */ 108 109 int 110 _init(void) 111 { 112 int status; 113 114 lofs_subrinit(); 115 status = mod_install(&modlinkage); 116 if (status != 0) { 117 /* 118 * Cleanup previously initialized work. 119 */ 120 lofs_subrfini(); 121 } 122 123 return (status); 124 } 125 126 /* 127 * Don't allow the lofs module to be unloaded for now. 128 * There is a memory leak if it gets unloaded. 129 */ 130 131 int 132 _fini(void) 133 { 134 return (EBUSY); 135 } 136 137 int 138 _info(struct modinfo *modinfop) 139 { 140 return (mod_info(&modlinkage, modinfop)); 141 } 142 143 144 static int lofsfstype; 145 vfsops_t *lo_vfsops; 146 147 /* 148 * lo mount vfsop 149 * Set up mount info record and attach it to vfs struct. 150 */ 151 /*ARGSUSED*/ 152 static int 153 lo_mount(struct vfs *vfsp, 154 struct vnode *vp, 155 struct mounta *uap, 156 struct cred *cr) 157 { 158 int error; 159 struct vnode *srootvp = NULL; /* the server's root */ 160 struct vnode *realrootvp; 161 struct loinfo *li; 162 int nodev; 163 164 nodev = vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL); 165 166 if ((error = secpolicy_fs_mount(cr, vp, vfsp)) != 0) 167 return (EPERM); 168 169 /* 170 * Loopback devices which get "nodevices" added can be done without 171 * "nodevices" set because we cannot import devices into a zone 172 * with loopback. Note that we have all zone privileges when 173 * this happens; if not, we'd have gotten "nosuid". 174 */ 175 if (!nodev && vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 176 vfs_setmntopt(vfsp, MNTOPT_DEVICES, NULL, VFS_NODISPLAY); 177 178 mutex_enter(&vp->v_lock); 179 if (!(uap->flags & MS_OVERLAY) && 180 (vp->v_count != 1 || (vp->v_flag & VROOT))) { 181 mutex_exit(&vp->v_lock); 182 return (EBUSY); 183 } 184 mutex_exit(&vp->v_lock); 185 186 /* 187 * Find real root, and make vfs point to real vfs 188 */ 189 190 if (error = lookupname(uap->spec, (uap->flags & MS_SYSSPACE) ? 191 UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, &realrootvp)) 192 return (error); 193 194 /* 195 * Enforce MAC policy if needed. 196 * 197 * Loopback mounts must not allow writing up. The dominance test 198 * is intended to prevent a global zone caller from accidentally 199 * creating write-up conditions between two labeled zones. 200 * Local zones can't violate MAC on their own without help from 201 * the global zone because they can't name a pathname that 202 * they don't already have. 203 * 204 * The special case check for the NET_MAC_AWARE process flag is 205 * to support the case of the automounter in the global zone. We 206 * permit automounting of local zone directories such as home 207 * directories, into the global zone as required by setlabel, 208 * zonecopy, and saving of desktop sessions. Such mounts are 209 * trusted not to expose the contents of one zone's directories 210 * to another by leaking them through the global zone. 211 */ 212 if (is_system_labeled() && crgetzoneid(cr) == GLOBAL_ZONEID) { 213 char specname[MAXPATHLEN]; 214 zone_t *from_zptr; 215 zone_t *to_zptr; 216 217 if (vnodetopath(NULL, realrootvp, specname, 218 sizeof (specname), CRED()) != 0) { 219 VN_RELE(realrootvp); 220 return (EACCES); 221 } 222 223 from_zptr = zone_find_by_path(specname); 224 to_zptr = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 225 226 /* 227 * Special case for scratch zones used for Live Upgrade: 228 * this is used to mount the zone's root from /root to /a in 229 * the scratch zone. As with the other special case, this 230 * appears to be outside of the zone because it's not under 231 * the zone rootpath, which is $ZONEPATH/lu in the scratch 232 * zone case. 233 */ 234 235 if (from_zptr != to_zptr && 236 !(to_zptr->zone_flags & ZF_IS_SCRATCH)) { 237 /* 238 * We know at this point that the labels aren't equal 239 * because the zone pointers aren't equal, and zones 240 * can't share a label. 241 * 242 * If the source is the global zone then making 243 * it available to a local zone must be done in 244 * read-only mode as the label will become admin_low. 245 * 246 * If it is a mount between local zones then if 247 * the current process is in the global zone and has 248 * the NET_MAC_AWARE flag, then regular read-write 249 * access is allowed. If it's in some other zone, but 250 * the label on the mount point dominates the original 251 * source, then allow the mount as read-only 252 * ("read-down"). 253 */ 254 if (from_zptr->zone_id == GLOBAL_ZONEID) { 255 /* make the mount read-only */ 256 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 257 } else { /* cross-zone mount */ 258 if (to_zptr->zone_id == GLOBAL_ZONEID && 259 /* LINTED: no consequent */ 260 getpflags(NET_MAC_AWARE, cr) != 0) { 261 /* Allow the mount as read-write */ 262 } else if (bldominates( 263 label2bslabel(to_zptr->zone_slabel), 264 label2bslabel(from_zptr->zone_slabel))) { 265 /* make the mount read-only */ 266 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 267 } else { 268 VN_RELE(realrootvp); 269 zone_rele(to_zptr); 270 zone_rele(from_zptr); 271 return (EACCES); 272 } 273 } 274 } 275 zone_rele(to_zptr); 276 zone_rele(from_zptr); 277 } 278 279 /* 280 * realrootvp may be an AUTOFS node, in which case we perform a 281 * VOP_ACCESS() to trigger the mount of the intended filesystem. 282 * This causes a loopback mount of the intended filesystem instead 283 * of the AUTOFS filesystem. 284 * 285 * If a lofs mount creates a mount loop (such that a lofs vfs is 286 * mounted on an autofs node and that lofs vfs points back to the 287 * autofs node which it is mounted on) then a VOP_ACCESS call will 288 * create a deadlock. Once this deadlock is released, VOP_ACCESS will 289 * return EINTR. In such a case we don't want the lofs vfs to be 290 * created as the loop could panic the system. 291 */ 292 if ((error = VOP_ACCESS(realrootvp, 0, 0, cr, NULL)) != 0) { 293 VN_RELE(realrootvp); 294 return (error); 295 } 296 297 /* 298 * We're interested in the top most filesystem. 299 * This is specially important when uap->spec is a trigger 300 * AUTOFS node, since we're really interested in mounting the 301 * filesystem AUTOFS mounted as result of the VOP_ACCESS() 302 * call not the AUTOFS node itself. 303 */ 304 if (vn_mountedvfs(realrootvp) != NULL) { 305 if (error = traverse(&realrootvp)) { 306 VN_RELE(realrootvp); 307 return (error); 308 } 309 } 310 311 /* 312 * Allocate a vfs info struct and attach it 313 */ 314 li = kmem_zalloc(sizeof (struct loinfo), KM_SLEEP); 315 li->li_realvfs = realrootvp->v_vfsp; 316 li->li_mountvfs = vfsp; 317 318 /* 319 * Set mount flags to be inherited by loopback vfs's 320 */ 321 if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) { 322 li->li_mflag |= VFS_RDONLY; 323 } 324 if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { 325 li->li_mflag |= (VFS_NOSETUID|VFS_NODEVICES); 326 } 327 if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) { 328 li->li_mflag |= VFS_NODEVICES; 329 } 330 if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) { 331 li->li_mflag |= VFS_NOSETUID; 332 } 333 /* 334 * Permissive flags are added to the "deny" bitmap. 335 */ 336 if (vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL)) { 337 li->li_dflag |= VFS_XATTR; 338 } 339 if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) { 340 li->li_dflag |= VFS_NBMAND; 341 } 342 343 /* 344 * Propagate inheritable mount flags from the real vfs. 345 */ 346 if ((li->li_realvfs->vfs_flag & VFS_RDONLY) && 347 !vfs_optionisset(vfsp, MNTOPT_RO, NULL)) 348 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 349 VFS_NODISPLAY); 350 if ((li->li_realvfs->vfs_flag & VFS_NOSETUID) && 351 !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) 352 vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 353 VFS_NODISPLAY); 354 if ((li->li_realvfs->vfs_flag & VFS_NODEVICES) && 355 !vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 356 vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 357 VFS_NODISPLAY); 358 /* 359 * Permissive flags such as VFS_XATTR, as opposed to restrictive flags 360 * such as VFS_RDONLY, are handled differently. An explicit 361 * MNTOPT_NOXATTR should override the underlying filesystem's VFS_XATTR. 362 */ 363 if ((li->li_realvfs->vfs_flag & VFS_XATTR) && 364 !vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL) && 365 !vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) 366 vfs_setmntopt(vfsp, MNTOPT_XATTR, NULL, 367 VFS_NODISPLAY); 368 if ((li->li_realvfs->vfs_flag & VFS_NBMAND) && 369 !vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL) && 370 !vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) 371 vfs_setmntopt(vfsp, MNTOPT_NBMAND, NULL, 372 VFS_NODISPLAY); 373 374 li->li_refct = 0; 375 vfsp->vfs_data = (caddr_t)li; 376 vfsp->vfs_bcount = 0; 377 vfsp->vfs_fstype = lofsfstype; 378 vfsp->vfs_bsize = li->li_realvfs->vfs_bsize; 379 380 vfsp->vfs_dev = li->li_realvfs->vfs_dev; 381 vfsp->vfs_fsid.val[0] = li->li_realvfs->vfs_fsid.val[0]; 382 vfsp->vfs_fsid.val[1] = li->li_realvfs->vfs_fsid.val[1]; 383 384 if (vfs_optionisset(vfsp, MNTOPT_LOFS_NOSUB, NULL)) { 385 li->li_flag |= LO_NOSUB; 386 } 387 388 /* 389 * Propagate any VFS features 390 */ 391 392 vfs_propagate_features(li->li_realvfs, vfsp); 393 394 /* 395 * Setup the hashtable. If the root of this mount isn't a directory, 396 * there's no point in allocating a large hashtable. A table with one 397 * bucket is sufficient. 398 */ 399 if (realrootvp->v_type != VDIR) 400 lsetup(li, 1); 401 else 402 lsetup(li, 0); 403 404 /* 405 * Make the root vnode 406 */ 407 srootvp = makelonode(realrootvp, li, 0); 408 srootvp->v_flag |= VROOT; 409 li->li_rootvp = srootvp; 410 411 #ifdef LODEBUG 412 lo_dprint(4, "lo_mount: vfs %p realvfs %p root %p realroot %p li %p\n", 413 vfsp, li->li_realvfs, srootvp, realrootvp, li); 414 #endif 415 return (0); 416 } 417 418 /* 419 * Undo loopback mount 420 */ 421 static int 422 lo_unmount(struct vfs *vfsp, int flag, struct cred *cr) 423 { 424 struct loinfo *li; 425 426 if (secpolicy_fs_unmount(cr, vfsp) != 0) 427 return (EPERM); 428 429 /* 430 * Forced unmount is not supported by this file system 431 * and thus, ENOTSUP, is being returned. 432 */ 433 if (flag & MS_FORCE) 434 return (ENOTSUP); 435 436 li = vtoli(vfsp); 437 #ifdef LODEBUG 438 lo_dprint(4, "lo_unmount(%p) li %p\n", vfsp, li); 439 #endif 440 if (li->li_refct != 1 || li->li_rootvp->v_count != 1) { 441 #ifdef LODEBUG 442 lo_dprint(4, "refct %d v_ct %d\n", li->li_refct, 443 li->li_rootvp->v_count); 444 #endif 445 return (EBUSY); 446 } 447 VN_RELE(li->li_rootvp); 448 return (0); 449 } 450 451 /* 452 * Find root of lofs mount. 453 */ 454 static int 455 lo_root(struct vfs *vfsp, struct vnode **vpp) 456 { 457 *vpp = vtoli(vfsp)->li_rootvp; 458 #ifdef LODEBUG 459 lo_dprint(4, "lo_root(0x%p) = %p\n", vfsp, *vpp); 460 #endif 461 /* 462 * If the root of the filesystem is a special file, return the specvp 463 * version of the vnode. We don't save the specvp vnode in our 464 * hashtable since that's exclusively for lnodes. 465 */ 466 if (IS_DEVVP(*vpp)) { 467 struct vnode *svp; 468 469 svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, kcred); 470 if (svp == NULL) 471 return (ENOSYS); 472 *vpp = svp; 473 } else { 474 VN_HOLD(*vpp); 475 } 476 477 return (0); 478 } 479 480 /* 481 * Get file system statistics. 482 */ 483 static int 484 lo_statvfs(register struct vfs *vfsp, struct statvfs64 *sbp) 485 { 486 vnode_t *realrootvp; 487 488 #ifdef LODEBUG 489 lo_dprint(4, "lostatvfs %p\n", vfsp); 490 #endif 491 /* 492 * Using realrootvp->v_vfsp (instead of the realvfsp that was 493 * cached) is necessary to make lofs work woth forced UFS unmounts. 494 * In the case of a forced unmount, UFS stores a set of dummy vfsops 495 * in all the (i)vnodes in the filesystem. The dummy ops simply 496 * returns back EIO. 497 */ 498 (void) lo_realvfs(vfsp, &realrootvp); 499 if (realrootvp != NULL) 500 return (VFS_STATVFS(realrootvp->v_vfsp, sbp)); 501 else 502 return (EIO); 503 } 504 505 /* 506 * LOFS doesn't have any data or metadata to flush, pending I/O on the 507 * underlying filesystem will be flushed when such filesystem is synched. 508 */ 509 /* ARGSUSED */ 510 static int 511 lo_sync(struct vfs *vfsp, 512 short flag, 513 struct cred *cr) 514 { 515 #ifdef LODEBUG 516 lo_dprint(4, "lo_sync: %p\n", vfsp); 517 #endif 518 return (0); 519 } 520 521 /* 522 * Obtain the vnode from the underlying filesystem. 523 */ 524 static int 525 lo_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 526 { 527 vnode_t *realrootvp; 528 529 #ifdef LODEBUG 530 lo_dprint(4, "lo_vget: %p\n", vfsp); 531 #endif 532 (void) lo_realvfs(vfsp, &realrootvp); 533 if (realrootvp != NULL) 534 return (VFS_VGET(realrootvp->v_vfsp, vpp, fidp)); 535 else 536 return (EIO); 537 } 538 539 /* 540 * Free mount-specific data. 541 */ 542 static void 543 lo_freevfs(struct vfs *vfsp) 544 { 545 struct loinfo *li = vtoli(vfsp); 546 547 ldestroy(li); 548 kmem_free(li, sizeof (struct loinfo)); 549 } 550 551 static int 552 lofsinit(int fstyp, char *name) 553 { 554 static const fs_operation_def_t lo_vfsops_template[] = { 555 { VFSNAME_MOUNT, { .vfs_mount = lo_mount } }, 556 { VFSNAME_UNMOUNT, { .vfs_unmount = lo_unmount } }, 557 { VFSNAME_ROOT, { .vfs_root = lo_root } }, 558 { VFSNAME_STATVFS, { .vfs_statvfs = lo_statvfs } }, 559 { VFSNAME_SYNC, { .vfs_sync = lo_sync } }, 560 { VFSNAME_VGET, { .vfs_vget = lo_vget } }, 561 { VFSNAME_FREEVFS, { .vfs_freevfs = lo_freevfs } }, 562 { NULL, { NULL } } 563 }; 564 int error; 565 566 error = vfs_setfsops(fstyp, lo_vfsops_template, &lo_vfsops); 567 if (error != 0) { 568 cmn_err(CE_WARN, "lofsinit: bad vfs ops template"); 569 return (error); 570 } 571 572 error = vn_make_ops(name, lo_vnodeops_template, &lo_vnodeops); 573 if (error != 0) { 574 (void) vfs_freevfsops_by_type(fstyp); 575 cmn_err(CE_WARN, "lofsinit: bad vnode ops template"); 576 return (error); 577 } 578 579 lofsfstype = fstyp; 580 581 return (0); 582 }