diff --git a/sys/kern/vfs_mount.c.vnetmnt b/sys/kern/vfs_mount.c --- a/sys/kern/vfs_mount.c.vnetmnt +++ b/sys/kern/vfs_mount.c @@ -1287,7 +1287,18 @@ * Only privileged root, or (if MNT_USER is set) the user that * did the original mount is permitted to update it. */ - error = vfs_suser(mp, td); +#ifdef VNET_NFSD + /* + * For the case of mountd doing exports in a jail, don't + * call vfs_suser(). vfs_domount() has already checked that + * "root" is doing this and vfs_suser() will fail when + * the file system has been mounted outside the jail. + */ + error = 0; + if ((fsflags & MNT_EXPORTED) == 0 || !jailed(td->td_ucred) || + !prison_check_nfsd(td->td_ucred)) +#endif + error = vfs_suser(mp, td); if (error != 0) { vput(vp); return (error); @@ -1332,7 +1343,19 @@ * XXX The final recipients of VFS_MOUNT just overwrite the ndp they * get. No freeing of cn_pnbuf. */ - error = VFS_MOUNT(mp); +#ifdef VNET_NFSD + /* + * For the case of mountd doing exports from within a vnet prison, + * "from" is not set correctly such that VFS_MOUNT() will return ENOENT. + * It is not obvious that VFS_MOUNT() ever needs to be called when + * mountd is doing exports, but this check only applies to the + * specific case where it is running inside a vnet prison, for now. + */ + error = 0; + if ((fsflags & MNT_EXPORTED) == 0 || !jailed(td->td_ucred) || + !prison_check_nfsd(td->td_ucred)) +#endif + error = VFS_MOUNT(mp); export_error = 0; /* Process the export option. */ @@ -1487,6 +1510,14 @@ if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN) return (ENAMETOOLONG); +#ifdef VNET_NFSD + if ((fsflags & MNT_EXPORTED) != 0 && jailed(td->td_ucred) && + prison_check_nfsd(td->td_ucred)) { + error = priv_check(td, PRIV_NFS_DAEMON); + if (error) + return (error); + } else +#endif if (jailed(td->td_ucred) || usermount == 0) { if ((error = priv_check(td, PRIV_VFS_MOUNT)) != 0) return (error);