diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1304,6 +1304,7 @@ static int vfs_domount_update( struct thread *td, /* Calling thread. */ + struct vfsconf *vfsp, /* Caller's idea of VFS. */ struct vnode *vp, /* Mount point vnode. */ uint64_t fsflags, /* Flags common to all filesystems. */ bool jail_export, /* Got export option in vnet prison. */ @@ -1365,6 +1366,16 @@ vput(vp); return (error); } + /* + * Userland code might have raced with another mount operation, e.g. + * when trying to update an autofs direct map mount. If the caller's + * idea of what VFS this should be is not correct, then deny the + * update. + */ + if (mp->mnt_vfc != vfsp) { + vput(vp); + return (EINVAL); + } if (vfs_busy(mp, MBF_NOWAIT)) { vput(vp); return (EBUSY); @@ -1618,15 +1629,13 @@ /* Load KLDs before we lock the covered vnode to avoid reversals. */ vfsp = NULL; - if ((fsflags & MNT_UPDATE) == 0) { - /* Don't try to load KLDs if we're mounting the root. */ - if (fsflags & MNT_ROOTFS) { - if ((vfsp = vfs_byname(fstype)) == NULL) - return (ENODEV); - } else { - if ((vfsp = vfs_byname_kld(fstype, td, &error)) == NULL) - return (error); - } + /* Don't try to load KLDs if we're mounting the root or updating. */ + if ((fsflags & MNT_ROOTFS) != 0 || (fsflags & MNT_UPDATE) != 0) { + if ((vfsp = vfs_byname(fstype)) == NULL) + return (ENODEV); + } else { + if ((vfsp = vfs_byname_kld(fstype, td, &error)) == NULL) + return (error); } /* @@ -1671,8 +1680,8 @@ } free(pathbuf, M_TEMP); } else - error = vfs_domount_update(td, vp, fsflags, jail_export, - optlist); + error = vfs_domount_update(td, vfsp, vp, fsflags, + jail_export, optlist); out: NDFREE_PNBUF(&nd); diff --git a/usr.sbin/autofs/automount.c b/usr.sbin/autofs/automount.c --- a/usr.sbin/autofs/automount.c +++ b/usr.sbin/autofs/automount.c @@ -262,6 +262,7 @@ flush_caches(void) { struct statfs *mntbuf; + struct statfs statbuf; int i, nitems; nitems = getmntinfo(&mntbuf, MNT_WAIT); @@ -276,6 +277,21 @@ mntbuf[i].f_mntonname); continue; } + /* + * A direct map mountpoint may have been mounted over, in + * which case we can't MNT_UPDATE it. There's an obvious race + * condition remaining here, but that has to be fixed in the + * kernel. + */ + if (statfs(mntbuf[i].f_mntonname, &statbuf) != 0) { + log_err(1, "cannot statfs %s", mntbuf[i].f_mntonname); + continue; + } + if (strcmp(statbuf.f_fstypename, "autofs") != 0) { + log_debugx("skipping %s, filesystem type is not autofs", + mntbuf[i].f_mntonname); + continue; + } flush_autofs(mntbuf[i].f_mntonname); }