changeset 7881:fbb450806b75

Labeled tmpfs support Take 3 of the labeled tmpfs support. With the change to sysattr_list(), it is no longer a problem to return EINVAL on any of the default system attributes in tmp_setattr. We will still need to address the removal of VFSFT_XVATTR from tmpfs when we rebase to snv_100+ by introducing a VFSFT_XVATTR_SECCTX or implementing the default system attributes in tmpfs. The root directory of a tmpfs mount is initially labeled from the mount point directory, as with the existing uid/gid/mode assignment. Thus, for example, one can umount /tmp from single-user mode and setfilecon the mount point directory to system_u:object_r:tmp_t in order to get the tmpfs mount to pick up that context on subsequent mounts. John also found that we can label the other tmpfs mount points by moving setfiles to /sbin and invoking it from /lib/svc/method/fs-minimal on /tmp, /var/run and any other tmpfs mount points. Files and directories created in the tmpfs mount are then labeled via the fmac_vnode_create and post_create hooks as in ZFS, except that we do not need to set up an xvattr on the file creation code path since there is no storage of the secctx and we only need to set up the incore secid on the vnode. Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the secctx from the secid in order to pass back to userspace. Upon tmp_setattr, the secpolicy hook will ultimately call fmac_vnode_set_secctx() and update the vnode secid, so we only need to set the return flag for XAT_SECCTX. A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a FMAC permission check whenever the existing tmpfs permission checks would grant access. This uses conventional modes and thus does not pass V_ACE_MASK. A call to fmac_vnode_remove() is inserted into tmp_sticky_remove_access() as an initial cut at mediating removal of files in tmpfs, although this may need to be taken to the callers when rename checking is introduced. Webrev at: http://cr.opensolaris.org/~sds/tmpfs3/
author Stephen Smalley <sds@tycho.nsa.gov>
date Thu, 09 Oct 2008 15:17:07 -0400
parents 83bea1900f31
children 5619e6e27d7c
files usr/src/uts/common/fmac/fmac.c usr/src/uts/common/fs/tmpfs/tmp_subr.c usr/src/uts/common/fs/tmpfs/tmp_vfsops.c usr/src/uts/common/fs/tmpfs/tmp_vnops.c usr/src/uts/common/sys/fmac/fmac.h
diffstat 5 files changed, 103 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fmac/fmac.c	Thu Oct 09 15:16:55 2008 -0400
+++ b/usr/src/uts/common/fmac/fmac.c	Thu Oct 09 15:17:07 2008 -0400
@@ -254,6 +254,40 @@
 }
 
 int
+fmac_vnode_get_secctx(vnode_t *vp, vattr_t *vap)
+{
+	xvattr_t *xvap = (xvattr_t *)vap;
+	xoptattr_t *xoap;
+	security_context_t scontext;
+	uint32_t scontext_len;
+	int error;
+
+	if (!fmac_enabled)
+		return (0);
+
+	xoap = xva_getxoptattr(xvap);
+	if (!xoap)
+		return (0);
+
+	if (!XVA_ISSET_REQ(xvap, XAT_SECCTX))
+		return (0);
+
+	error = security_sid_to_context(vp->v_secid, &scontext, &scontext_len);
+	if (error)
+		return (error);
+
+	if (scontext_len > sizeof (xoap->xoa_secctx)) {
+		security_context_free(scontext);
+		return (EINVAL);
+	}
+
+	(void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx));
+	XVA_SET_RTN(xvap, XAT_SECCTX);
+	security_context_free(scontext);
+	return (0);
+}
+
+int
 fmac_vnode_create(vnode_t *dvp, char *name, xvattr_t *xvap, vattr_t **vapp,
     cred_t *cr, security_id_t *secidp)
 {
@@ -303,6 +337,15 @@
 	if (error)
 		return (error);
 
+	if (!xvap) {
+		/*
+		 * Caller only wants the secid, not an xvattr w/ secctx.
+		 * tmpfs is one such example.
+		 */
+		*secidp = secid;
+		return (0);
+	}
+
 	if (!(vap->va_mask & AT_XVATTR)) {
 		/*
 		 * If the vattr is not already an xvattr, then wrap the
--- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c	Thu Oct 09 15:16:55 2008 -0400
+++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c	Thu Oct 09 15:17:07 2008 -0400
@@ -42,6 +42,7 @@
 #include <sys/kmem.h>
 #include <sys/atomic.h>
 #include <sys/policy.h>
+#include <sys/fmac/fmac.h>
 #include <sys/fs/tmp.h>
 #include <sys/fs/tmpnode.h>
 
@@ -52,6 +53,8 @@
 {
 	struct tmpnode *tp = vtp;
 	int shift = 0;
+	int error = 0;
+
 	/*
 	 * Check access based on owner, group and
 	 * public permissions in tmpnode.
@@ -65,10 +68,14 @@
 	/* compute missing mode bits */
 	mode &= ~(tp->tn_mode << shift);
 
-	if (mode == 0)
-		return (0);
+	if (mode)
+		error = secpolicy_vnode_access(cred, TNTOV(tp), tp->tn_uid,
+		    mode);
 
-	return (secpolicy_vnode_access(cred, TNTOV(tp), tp->tn_uid, mode));
+	if (!error)
+		error = fmac_vnode_access(TNTOV(tp), mode, 0, cred, B_TRUE);
+
+	return (error);
 }
 
 /*
@@ -86,15 +93,19 @@
 	struct cred *cr)
 {
 	uid_t uid = crgetuid(cr);
+	int error = 0;
 
 	if ((dir->tn_mode & S_ISVTX) &&
 	    uid != dir->tn_uid &&
 	    uid != entry->tn_uid &&
 	    (entry->tn_type != VREG ||
 	    tmp_taccess(entry, VWRITE, cr) != 0))
-		return (secpolicy_vnode_remove(cr));
+		error = secpolicy_vnode_remove(cr);
 
-	return (0);
+	if (!error)
+		error = fmac_vnode_remove(TNTOV(dir), TNTOV(entry), NULL, cr);
+
+	return (error);
 }
 
 /*
--- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c	Thu Oct 09 15:16:55 2008 -0400
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c	Thu Oct 09 15:17:07 2008 -0400
@@ -342,6 +342,7 @@
 
 	rw_enter(&tp->tn_rwlock, RW_WRITER);
 	TNTOV(tp)->v_flag |= VROOT;
+	TNTOV(tp)->v_secid = mvp->v_secid;
 
 	/*
 	 * If the getattr succeeded, use its results.  Otherwise allow
--- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c	Thu Oct 09 15:16:55 2008 -0400
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c	Thu Oct 09 15:17:07 2008 -0400
@@ -64,6 +64,7 @@
 #include <sys/vm.h>
 #include <sys/vtrace.h>
 #include <sys/policy.h>
+#include <sys/fmac/fmac.h>
 #include <fs/fs_subr.h>
 
 static int	tmp_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
@@ -702,7 +703,8 @@
 	 */
 	vap->va_nblocks = (fsblkcnt64_t)btodb(ptob(btopr(vap->va_size)));
 	mutex_exit(&tp->tn_tlock);
-	return (0);
+
+	return (fmac_vnode_get_secctx(vp, vap));
 }
 
 /*ARGSUSED4*/
@@ -718,14 +720,34 @@
 	struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
 	int error = 0;
 	struct vattr *get;
+	xvattr_t *xvap = (xvattr_t *)vap;
 	long mask;
 
 	/*
 	 * Cannot set these attributes
 	 */
-	if ((vap->va_mask & AT_NOSET) || (vap->va_mask & AT_XVATTR))
+	if (vap->va_mask & AT_NOSET)
 		return (EINVAL);
 
+	/*
+	 * Only support XAT_SECCTX presently.
+	 */
+	if (vap->va_mask & AT_XVATTR) {
+		if (XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
+		    XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
+		    XVA_ISSET_REQ(xvap, XAT_SYSTEM) ||
+		    XVA_ISSET_REQ(xvap, XAT_READONLY) ||
+		    XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
+		    XVA_ISSET_REQ(xvap, XAT_NOUNLINK) ||
+		    XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) ||
+		    XVA_ISSET_REQ(xvap, XAT_APPENDONLY) ||
+		    XVA_ISSET_REQ(xvap, XAT_NODUMP) ||
+		    XVA_ISSET_REQ(xvap, XAT_OPAQUE) ||
+		    XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) ||
+		    XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+			return (EINVAL);
+	}
+
 	mutex_enter(&tp->tn_tlock);
 
 	get = &tp->tn_attr;
@@ -741,6 +763,11 @@
 
 	mask = vap->va_mask;
 
+	if ((mask & AT_XVATTR) && XVA_ISSET_REQ(xvap, XAT_SECCTX)) {
+		/* vnode secid was updated during the secpolicy call. */
+		XVA_SET_RTN(xvap, XAT_SECCTX);
+	}
+
 	if (mask & AT_MODE) {
 		get->va_mode &= S_IFMT;
 		get->va_mode |= vap->va_mode & ~S_IFMT;
@@ -937,6 +964,7 @@
 	struct tmpnode *self;
 	int error;
 	struct tmpnode *oldtp;
+	security_id_t	secid;
 
 again:
 	parent = (struct tmpnode *)VTOTN(dvp);
@@ -1021,6 +1049,10 @@
 	if (error != ENOENT)
 		return (error);
 
+	error = fmac_vnode_create(dvp, nm, NULL, &vap, cred, &secid);
+	if (error)
+		return (error);
+
 	rw_enter(&parent->tn_rwlock, RW_WRITER);
 	error = tdirenter(tm, parent, nm, DE_CREATE,
 	    (struct tmpnode *)NULL, (struct tmpnode *)NULL,
@@ -1057,6 +1089,8 @@
 			return (ENOSYS);
 		*vpp = newvp;
 	}
+
+	fmac_vnode_post_create(*vpp, secid);
 	TRACE_3(TR_FAC_TMPFS, TR_TMPFS_CREATE,
 	    "tmpfs create:dvp %p nm %s vpp %p", dvp, nm, vpp);
 	return (0);
@@ -1300,6 +1334,11 @@
 	struct tmpnode *self = NULL;
 	struct tmount *tm = (struct tmount *)VTOTM(dvp);
 	int error;
+	security_id_t	secid;
+
+	error = fmac_vnode_create(dvp, nm, NULL, &va, cred, &secid);
+	if (error)
+		return (error);
 
 	/* no new dirs allowed in xattr dirs */
 	if (parent->tn_flags & ISXATTR)
@@ -1333,6 +1372,7 @@
 	}
 	rw_exit(&parent->tn_rwlock);
 	*vpp = TNTOV(self);
+	fmac_vnode_post_create(*vpp, secid);
 	return (0);
 }
 
--- a/usr/src/uts/common/sys/fmac/fmac.h	Thu Oct 09 15:16:55 2008 -0400
+++ b/usr/src/uts/common/sys/fmac/fmac.h	Thu Oct 09 15:17:07 2008 -0400
@@ -88,6 +88,7 @@
 int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *);
 int fmac_vfs_root(vfs_t *, vnode_t *);
 int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *);
+int fmac_vnode_get_secctx(vnode_t *vp, vattr_t *vap);
 int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *,
     security_id_t *);
 void fmac_vnode_post_create(vnode_t *, security_id_t);