Add support for mounting single files in nullfs

The main use-case for this is to support mounting config files and
secrets into OCI containers. My current workaround copies the files into
the container which is messy and risks secrets leaking into container
images if the cleanup fails.

This adds a VFCF flag to indicate whether the filesystem supports file
mounts and allows fspath to be either a directory or a file if the flag
is set.

Test Plan:
$ sudo mkdir -p /mnt
$ sudo touch /mnt/foo
$ sudo mount -t nullfs /COPYRIGHT /mnt/foo

Reviewed by:    mjg, kib
Tested by:      pho
This commit is contained in:
Doug Rabson 2022-11-23 14:51:13 +00:00
parent 78d35459a2
commit 521fbb722c
3 changed files with 40 additions and 8 deletions

View File

@ -156,6 +156,17 @@ nullfs_mount(struct mount *mp)
}
}
/*
* Lower vnode must be the same type as the covered vnode - we
* don't allow mounting directories to files or vice versa.
*/
if ((lowerrootvp->v_type != VDIR && lowerrootvp->v_type != VREG) ||
lowerrootvp->v_type != mp->mnt_vnodecovered->v_type) {
NULLFSDEBUG("nullfs_mount: target must be same type as fspath");
vput(lowerrootvp);
return (EINVAL);
}
xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
M_NULLFSMNT, M_WAITOK | M_ZERO);
@ -503,4 +514,4 @@ static struct vfsops null_vfsops = {
.vfs_unlink_lowervp = nullfs_unlink_lowervp,
};
VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL);
VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL | VFCF_FILEMOUNT);

View File

@ -1105,8 +1105,13 @@ vfs_domount_first(
error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN);
if (error == 0)
error = vinvalbuf(vp, V_SAVE, 0, 0);
if (error == 0 && vp->v_type != VDIR)
error = ENOTDIR;
if (vfsp->vfc_flags & VFCF_FILEMOUNT) {
if (error == 0 && vp->v_type != VDIR && vp->v_type != VREG)
error = EINVAL;
} else {
if (error == 0 && vp->v_type != VDIR)
error = ENOTDIR;
}
if (error == 0 && (fsflags & MNT_EMPTYDIR) != 0)
error = vfs_emptydir(vp);
if (error == 0) {
@ -1535,22 +1540,33 @@ vfs_domount(
/*
* Get vnode to be covered or mount point's vnode in case of MNT_UPDATE.
*/
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_SYSSPACE,
fspath);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1 | WANTPARENT,
UIO_SYSSPACE, fspath);
error = namei(&nd);
if (error != 0)
return (error);
NDFREE_PNBUF(&nd);
vp = nd.ni_vp;
if ((fsflags & MNT_UPDATE) == 0) {
if ((vp->v_vflag & VV_ROOT) != 0 &&
(fsflags & MNT_NOCOVER) != 0) {
vput(vp);
return (EBUSY);
error = EBUSY;
goto out;
}
pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
strcpy(pathbuf, fspath);
error = vn_path_to_global_path(td, vp, pathbuf, MNAMELEN);
/*
* Note: we allow any vnode type here. If the path sanity check
* succeeds, the type will be validated in vfs_domount_first
* above.
*/
if (vp->v_type == VDIR)
error = vn_path_to_global_path(td, vp, pathbuf,
MNAMELEN);
else
error = vn_path_to_global_path_hardlink(td, vp,
nd.ni_dvp, pathbuf, MNAMELEN,
nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen);
if (error == 0) {
error = vfs_domount_first(td, vfsp, pathbuf, vp,
fsflags, optlist);
@ -1559,6 +1575,10 @@ vfs_domount(
} else
error = vfs_domount_update(td, vp, fsflags, optlist);
out:
NDFREE_PNBUF(&nd);
vrele(nd.ni_dvp);
return (error);
}

View File

@ -678,6 +678,7 @@ struct ovfsconf {
#define VFCF_DELEGADMIN 0x00800000 /* supports delegated administration */
#define VFCF_SBDRY 0x01000000 /* Stop at Boundary: defer stop requests
to kernel->user (AST) transition */
#define VFCF_FILEMOUNT 0x02000000 /* allow mounting files */
typedef uint32_t fsctlop_t;