[PATCH] Updated jail mount/unmount patch

Martin Matuska mm at FreeBSD.org
Fri Jul 29 20:01:47 UTC 2011


After implementing a suggestion from pjd@, a new version of the patch is
attached, now using a more universal solution - vn_fullpath_global() in
the mount part.

Dňa 28. 7. 2011 16:59, Martin Matuska wrote / napísal(a):
> Please review my attached patch.
>
> The patch fixes f_mntonname with mount/unmount inside a jail with allow.mount enabled.
> Filesystems mountable in a jail require the VFCF_JAIL flag (currently only ZFS).
>
> With this patch, mount and unmount works both with enforce_statfs = 0 and enforce_statfs = 1.
> I suggest disabling mount/unmount for jails with enforce_statfs = 2, as this is contradictory and does not play well with or without this patch.
>
> I have successfully tested this patch with ZFS, nullfs and tmpfs.
>
> To enable nullfs for a jail, you have to modify tmpfs/tmpfs_vfsops.c and recompile the tmpfs module:
> -VFS_SET(tmpfs_vfsops, tmpfs, 0);
> +VFS_SET(tmpfs_vfsops, tmpfs, VFCF_JAIL);
>
> To enable tmpfs for a jail, you have to modify nullfs/null_vfsops.c and recompile the nullfs module:
> -VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK);
> +VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL);
>
> The filesystems can be successfully mounted/unmounted inside a jail and also unmounted from the parent host without problems.
>
> The mount inside jail, a jail needs allow.mount=1 and enforce.statfs=0 or enforce.statfs=1, for more information see jail(8)
> I assume other filesystem not dealing with devices may work correctly with this patch, too (e.g. nfs).
>
> With jailed nullfs we can run tinderbox in a jail ;)
>
> Please review, comment and/or test my attached patch.
>
> Cheers,
> mm
-- 
Martin Matuska
FreeBSD committer
http://blog.vx.sk

-------------- next part --------------
Index: sys/kern/kern_jail.c
===================================================================
--- sys/kern/kern_jail.c	(revision 224471)
+++ sys/kern/kern_jail.c	(working copy)
@@ -3858,7 +3858,8 @@
 	case PRIV_VFS_UNMOUNT:
 	case PRIV_VFS_MOUNT_NONUSER:
 	case PRIV_VFS_MOUNT_OWNER:
-		if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT)
+		if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT &&
+			cred->cr_prison->pr_enforce_statfs != 2)
 			return (0);
 		else
 			return (EPERM);
Index: sys/kern/vfs_mount.c
===================================================================
--- sys/kern/vfs_mount.c	(revision 224471)
+++ sys/kern/vfs_mount.c	(working copy)
@@ -745,7 +745,6 @@
 vfs_domount_first(
 	struct thread *td,		/* Calling thread. */
 	struct vfsconf *vfsp,		/* File system type. */
-	char *fspath,			/* Mount path. */
 	struct vnode *vp,		/* Vnode to be covered. */
 	int fsflags,			/* Flags common to all filesystems. */
 	struct vfsoptlist **optlist	/* Options local to the filesystem. */
@@ -755,11 +754,23 @@
 	struct mount *mp;
 	struct vnode *newdp;
 	int error;
+	char *fspath, *fbuf;
 
 	mtx_assert(&Giant, MA_OWNED);
 	ASSERT_VOP_ELOCKED(vp, __func__);
 	KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here"));
 
+	/* Construct global filesystem path from vp */
+	error = vn_fullpath_global(td, vp, &fspath, &fbuf);
+	if (error == 0 && strlen(fspath) >= MNAMELEN)
+		error = ENAMETOOLONG;
+	if (error != 0) {
+		vput(vp);
+		if (fbuf != NULL)
+			free(fbuf, M_TEMP);
+		return(error);
+	}
+
 	/*
 	 * If the user is not root, ensure that they own the directory
 	 * onto which we are attempting to mount.
@@ -781,12 +792,14 @@
 	}
 	if (error != 0) {
 		vput(vp);
+		free(fbuf, M_TEMP);
 		return (error);
 	}
 	VOP_UNLOCK(vp, 0);
 
 	/* Allocate and initialize the filesystem. */
 	mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred);
+	free(fbuf, M_TEMP);
 	/* XXXMAC: pass to vfs_mount_alloc? */
 	mp->mnt_optnew = *optlist;
 	/* Set the mount level flags. */
@@ -1070,7 +1083,7 @@
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vp = nd.ni_vp;
 	if ((fsflags & MNT_UPDATE) == 0) {
-		error = vfs_domount_first(td, vfsp, fspath, vp, fsflags,
+		error = vfs_domount_first(td, vfsp, vp, fsflags,
 		    optlist);
 	} else {
 		error = vfs_domount_update(td, vp, fsflags, optlist);
@@ -1105,7 +1118,7 @@
 	} */ *uap;
 {
 	struct mount *mp;
-	char *pathbuf;
+	char *pathbuf, *rpathbuf;
 	int error, id0, id1;
 
 	AUDIT_ARG_VALUE(uap->flags);
@@ -1140,12 +1153,27 @@
 		mtx_unlock(&mountlist_mtx);
 	} else {
 		AUDIT_ARG_UPATH1(td, pathbuf);
+		/*
+		 * If we are jailed and enforce_statfs=1
+		 * construct real filesystem path
+		 */
+		rpathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+		if (jailed(td->td_ucred) &&
+		    td->td_ucred->cr_prison->pr_enforce_statfs == 1 &&
+		    strcmp(td->td_ucred->cr_prison->pr_path, "/") != 0) {
+			strlcpy(rpathbuf, td->td_ucred->cr_prison->pr_path,
+			    MNAMELEN);
+			strlcat(rpathbuf, pathbuf, MNAMELEN);
+		} else {
+			strlcpy(rpathbuf, pathbuf, MNAMELEN);
+		}
 		mtx_lock(&mountlist_mtx);
 		TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
-			if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0)
+			if (strcmp(mp->mnt_stat.f_mntonname, rpathbuf) == 0)
 				break;
 		}
 		mtx_unlock(&mountlist_mtx);
+		free(rpathbuf, M_TEMP);
 	}
 	free(pathbuf, M_TEMP);
 	if (mp == NULL) {


More information about the freebsd-current mailing list