changeset 7867:19259f972546

Mediate create and link Apply directory and file permission checks on create and link operations. This extends the existing fmac_vnode_create() hook to apply dir:add_name and file:create permission checks and adds a new fmac_vnode_link() hook to apply dir:add_name and file:link permission checks. Other changes include: - pass the link name to audit for inclusion in avc messages, - fix memory leak of security context in fmac_vnode_create(), - pass the vnode to audit on the fmac_exec() checks so that path= info is included in avc messages. The issue of unifying this logic with the corresponding filesystem access checking is deferred to a future patch. Sample avc output with this patch applied: avc: denied { add_name } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100779 comm=ln path=/etc name=foo avc: denied { link } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100779 comm=ln path=/etc/shadow name=foo
author Stephen Smalley <sds@tycho.nsa.gov>
date Wed, 17 Sep 2008 13:46:26 -0400
parents ff1aaba25d57
children 9efedf760333
files usr/src/uts/common/fmac/avc.c usr/src/uts/common/fmac/fmac.c usr/src/uts/common/fs/vnode.c usr/src/uts/common/sys/fmac/avc.h usr/src/uts/common/sys/fmac/fmac.h
diffstat 5 files changed, 79 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fmac/avc.c	Tue Sep 16 16:12:50 2008 -0400
+++ b/usr/src/uts/common/fmac/avc.c	Wed Sep 17 13:46:26 2008 -0400
@@ -567,6 +567,8 @@
 			vp = a->u.fs.vp;
 			if (vp && vp->v_path)
 				avc_audit_append(" path=%s", vp->v_path);
+			if (a->u.fs.name)
+				avc_audit_append(" name=%s", a->u.fs.name);
 			break;
 		}
 	}
--- a/usr/src/uts/common/fmac/fmac.c	Tue Sep 16 16:12:50 2008 -0400
+++ b/usr/src/uts/common/fmac/fmac.c	Wed Sep 17 13:46:26 2008 -0400
@@ -262,8 +262,7 @@
 	uint32_t scontext_len;
 	xoptattr_t *xoap;
 	int error;
-
-	_NOTE(ARGUNUSED(name));	/* future use in audit message */
+	avc_audit_data_t ad;
 
 	if (!fmac_enabled)
 		return (0);
@@ -284,6 +283,24 @@
 
 	cr_secid = crgetsecid(cr);
 
+	error = security_transition_sid(cr_secid, dvp->v_secid, sclass,
+	    &secid);
+	if (error)
+		return (error);
+
+	AVC_AUDIT_DATA_INIT(&ad, FS);
+	ad.u.fs.vp = dvp;
+	ad.u.fs.name = name;
+
+	error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR,
+	    DIR__ADD_NAME, &ad);
+	if (error)
+		return (error);
+
+	error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad);
+	if (error)
+		return (error);
+
 	/*
 	 * Wrap the vattr with an xvattr so we can pass the
 	 * secctx to the fs code.
@@ -293,32 +310,30 @@
 	xvap->xva_vattr.va_mask |= AT_XVATTR; /* reset after memcpy */
 	XVA_SET_REQ(xvap, XAT_SECCTX);
 
-	error = security_transition_sid(cr_secid, dvp->v_secid, sclass,
-	    &secid);
-	if (error)
-		return (error);
-
 	error = security_sid_to_context(secid, &scontext, &scontext_len);
 	if (error)
 		return (error);
 
 	if (scontext_len > sizeof (xoap->xoa_secctx))
-		return (EINVAL);
+		goto inval;
 
 	xoap = xva_getxoptattr(xvap);
 	if (!xoap)
-		return (EINVAL);
+		goto inval;
 	(void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx));
 
-	*secidp = secid;
-
 	/*
 	 * Switch the vap pointer to the newly populated xvattr.
 	 * fop_create/fop_mkdir will then pass the xvattr along to
 	 * the underlying fs code.  The original vattr is not mutated.
 	 */
 	*vapp = &xvap->xva_vattr;
+	*secidp = secid;
+	security_context_free(scontext);
 	return (0);
+inval:
+	security_context_free(scontext);
+	return (EINVAL);
 }
 
 void
@@ -332,11 +347,47 @@
 }
 
 int
+fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
+    caller_context_t *ct)
+{
+	security_id_t cr_secid;
+	security_class_t sclass;
+	int error;
+	vnode_t *realvp;
+	avc_audit_data_t ad;
+
+	if (!fmac_enabled)
+		return (0);
+
+	sclass = fmac_vtype_to_sclass(svp->v_type);
+	if (!sclass)
+		return (0);
+
+	if (VOP_REALVP(svp, &realvp, ct) == 0)
+		svp = realvp;
+
+	cr_secid = crgetsecid(cr);
+
+	AVC_AUDIT_DATA_INIT(&ad, FS);
+	ad.u.fs.vp = tdvp;
+	ad.u.fs.name = name;
+	error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR,
+	    DIR__ADD_NAME, &ad);
+	if (error)
+		return (error);
+
+	ad.u.fs.vp = svp;
+	return (avc_has_perm_audit(cr_secid, svp->v_secid, sclass,
+		    FILE__LINK, &ad));
+}
+
+int
 fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid,
     boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp)
 {
 	security_id_t prev_secid, secid;
 	int error;
+	avc_audit_data_t ad;
 
 	if (!fmac_enabled)
 		return (0);
@@ -351,8 +402,10 @@
 	}
 
 	if (prev_secid == secid) {
-		error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE,
-		    FILE__EXECUTE_NO_TRANS);
+		AVC_AUDIT_DATA_INIT(&ad, FS);
+		ad.u.fs.vp = vp;
+		error = avc_has_perm_audit(prev_secid, vp->v_secid,
+		    SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
 		if (error)
 			return (error);
 		*execsetid = B_FALSE;
@@ -365,8 +418,10 @@
 	if (error)
 		return (error);
 
-	error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE,
-	    FILE__ENTRYPOINT);
+	AVC_AUDIT_DATA_INIT(&ad, FS);
+	ad.u.fs.vp = vp;
+	error = avc_has_perm_audit(secid, vp->v_secid, SECCLASS_FILE,
+	    FILE__ENTRYPOINT, &ad);
 	if (error)
 		return (error);
 
--- a/usr/src/uts/common/fs/vnode.c	Tue Sep 16 16:12:50 2008 -0400
+++ b/usr/src/uts/common/fs/vnode.c	Wed Sep 17 13:46:26 2008 -0400
@@ -3445,6 +3445,10 @@
 
 	VOPXID_MAP_CR(tdvp, cr);
 
+	err = fmac_vnode_link(tdvp, svp, tnm, cr, ct);
+	if (err)
+		return (err);
+
 	err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags);
 	VOPSTATS_UPDATE(tdvp, link);
 	return (err);
--- a/usr/src/uts/common/sys/fmac/avc.h	Tue Sep 16 16:12:50 2008 -0400
+++ b/usr/src/uts/common/sys/fmac/avc.h	Wed Sep 17 13:46:26 2008 -0400
@@ -83,6 +83,7 @@
 	union 	{
 		struct {
 			struct vnode *vp;
+			char *name;
 		} fs;
 	} u;
 
--- a/usr/src/uts/common/sys/fmac/fmac.h	Tue Sep 16 16:12:50 2008 -0400
+++ b/usr/src/uts/common/sys/fmac/fmac.h	Wed Sep 17 13:46:26 2008 -0400
@@ -91,6 +91,8 @@
 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);
+int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
+    caller_context_t *ct);
 int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid,
     boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp);
 int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t);