changeset 7870:85ca241b1198

Mediate rename Apply directory and file permission checks on rename operations. To allow a distinction between rename and unlink checking on the source vnode, the fmac_vnode_remove() hook in zfs_zaccess_delete() introduced by the prior patch is moved to zfs_remove() and zfs_rmdir(), and a separate fmac_vnode_rename() hook is added to zfs_rename(). As with the remove/rmdir hooks, we have to hook zfs presently for rename since the source and target vnodes are only available there. Sample AVC output on a mv /etc/shadow- /etc/shadow: avc: denied { remove_name } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100813 comm=mv path=/etc avc: denied { rename } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100813 comm=mv path=/etc/shadow- avc: denied { add_name } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100813 comm=mv path=/etc avc: denied { unlink } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100813 comm=mv path=/etc/shadow
author Stephen Smalley <sds@tycho.nsa.gov>
date Thu, 18 Sep 2008 09:53:35 -0400
parents 9efedf760333
children bc3a0d3a4dc9
files usr/src/uts/common/fmac/fmac.c usr/src/uts/common/fs/zfs/zfs_acl.c usr/src/uts/common/fs/zfs/zfs_vnops.c usr/src/uts/common/sys/fmac/fmac.h
diffstat 4 files changed, 78 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fmac/fmac.c	Wed Sep 17 16:58:20 2008 -0400
+++ b/usr/src/uts/common/fmac/fmac.c	Thu Sep 18 09:53:35 2008 -0400
@@ -382,7 +382,7 @@
 }
 
 int
-fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr)
+fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr)
 {
 	security_id_t cr_secid;
 	security_class_t sclass;
@@ -401,6 +401,7 @@
 
 	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__REMOVE_NAME, &ad);
 	if (error)
@@ -415,6 +416,65 @@
 }
 
 int
+fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp,
+    cred_t *cr)
+{
+	security_id_t cr_secid;
+	security_class_t sclass, tclass;
+	access_vector_t av;
+	int error;
+	avc_audit_data_t ad;
+
+	if (!fmac_enabled)
+		return (0);
+
+	sclass = fmac_vtype_to_sclass(svp->v_type);
+	if (!sclass)
+		return (0);
+
+	cr_secid = crgetsecid(cr);
+
+	AVC_AUDIT_DATA_INIT(&ad, FS);
+
+	ad.u.fs.vp = sdvp;
+	error = avc_has_perm_audit(cr_secid, sdvp->v_secid, SECCLASS_DIR,
+	    DIR__REMOVE_NAME, &ad);
+	if (error)
+		return (error);
+
+	ad.u.fs.vp = svp;
+	error = avc_has_perm_audit(cr_secid, svp->v_secid, sclass,
+	    FILE__RENAME, &ad);
+	if (error)
+		return (error);
+
+	ad.u.fs.vp = tdvp;
+	error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR,
+	    DIR__ADD_NAME, &ad);
+	if (error)
+		return (error);
+
+	if (tvp) {
+		tclass = fmac_vtype_to_sclass(tvp->v_type);
+		if (!tclass)
+			return (0);
+
+		if (tclass == SECCLASS_DIR)
+			av = DIR__RMDIR;
+		else
+			av = FILE__UNLINK;
+
+		ad.u.fs.vp = tvp;
+		error = avc_has_perm_audit(cr_secid, tvp->v_secid, tclass, av,
+		    &ad);
+		if (error)
+			return (error);
+	}
+
+	return (0);
+}
+
+int
 fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid,
     boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp)
 {
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c	Wed Sep 17 16:58:20 2008 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c	Thu Sep 18 09:53:35 2008 -0400
@@ -50,7 +50,6 @@
 #include <sys/dmu.h>
 #include <sys/dnode.h>
 #include <sys/zap.h>
-#include <sys/fmac/fmac.h>
 #include "fs/fs_subr.h"
 #include <acl/acl_common.h>
 
@@ -2515,10 +2514,6 @@
 	boolean_t dzpcheck_privs = B_TRUE;
 	boolean_t zpcheck_privs = B_TRUE;
 
-	zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr);
-	if (zp_error)
-		return (zp_error);
-
 	/*
 	 * We want specific DELETE permissions to
 	 * take precedence over WRITE/EXECUTE.  We don't
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c	Wed Sep 17 16:58:20 2008 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c	Thu Sep 18 09:53:35 2008 -0400
@@ -74,6 +74,7 @@
 #include <sys/kidmap.h>
 #include <sys/cred_impl.h>
 #include <sys/attr.h>
+#include <sys/fmac/fmac.h>
 
 /*
  * Programming rules.
@@ -1446,6 +1447,10 @@
 		goto out;
 	}
 
+	error = fmac_vnode_remove(dvp, vp, name, cr);
+	if (error)
+		goto out;
+
 	vnevent_remove(vp, dvp, name, ct);
 
 	if (realnmp)
@@ -1802,6 +1807,10 @@
 		goto out;
 	}
 
+	error = fmac_vnode_remove(dvp, vp, name, cr);
+	if (error)
+		goto out;
+
 	vnevent_rmdir(vp, dvp, name, ct);
 
 	/*
@@ -3084,6 +3093,11 @@
 	if (error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr))
 		goto out;
 
+	error = fmac_vnode_rename(sdvp, ZTOV(szp), tdvp,
+	    tzp ? ZTOV(tzp) : NULL, cr);
+	if (error)
+		goto out;
+
 	if (ZTOV(szp)->v_type == VDIR) {
 		/*
 		 * Check to make sure rename is valid.
--- a/usr/src/uts/common/sys/fmac/fmac.h	Wed Sep 17 16:58:20 2008 -0400
+++ b/usr/src/uts/common/sys/fmac/fmac.h	Thu Sep 18 09:53:35 2008 -0400
@@ -93,7 +93,9 @@
 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_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr);
+int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr);
+int fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp,
+    cred_t *cr);
 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);