changeset 7878:08be291fa804

[fmac-discuss] [PATCH] Move fmac_vnode_access() hook to zfs_zaccess() Extend fmac_vnode_access() to understand ACE masks as well as traditional modes, and move the calls to it from fop_access() and zfs_create() into zfs_zaccess(). The access functions of other filesystems would need to be similarly instrumented, although they can pass conventional modes rather than ACE masks since fmac_vnode_access() understands both and distinguishes them based on flags. Note btw that extending fmac_vnode_access() to understand ACE masks is required regardless of whether we call it from fop_access() or zfs_zaccess() since callers of VOP_ACCESS() can pass ACE masks (as in the nfs4 and smbsrv cases). fmac_vnode_access() is only called if the normal zfs_zaccess() logic would grant the access (i.e. either the base DAC logic or the secpolicy hook authorized it). The secpolicy hook is not allowed to override a FMAC denial. One immediate benefit of taking the FMAC hook into zfs_zaccess is that we get proper checking against the base file when a named attribute is accessed, e.g. runat /etc/passwd cp /tmp/foo attr.1 fails as expected with a setattr denial. We also gain more complete coverage of file operations. I looked at moving the fmac_vnode_access() hook inside of zfs_zaccess_common(), but it seemed better to do it in zfs_zaccess() because: 1) We can then place it after both the base DAC logic and the privilege check. 2) We do not gain any benefit from checking all calls to zfs_zaccess_common() since other callers like zfs_zaccess_delete() and _rename() short-circuit their checking if access to the directory is granted, whereas we want checking against the target file in all cases and thus still need our separate hooks for those operations. Some of the other FMAC checks may be obsoleted by taking fmac_vnode_access() into zfs_zaccess(), but this requires a case-by-case review and testing as callers of zfs_zaccess() do not always honor a denial from it (can be overridden by other secpolicy calls), as in the setattr case. This is relative to the prior patch for the create hooks. Webrev is available at: http://cr.opensolaris.org/~sds/zaccess/
author Stephen Smalley <sds@tycho.nsa.gov>
date Tue, 07 Oct 2008 11:13:46 -0400
parents 098ba4106c40
children 2b795f3baa58
files usr/src/uts/common/fmac/fmac.c usr/src/uts/common/fs/vnode.c usr/src/uts/common/fs/zfs/zfs_acl.c usr/src/uts/common/fs/zfs/zfs_vnops.c
diffstat 4 files changed, 57 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fmac/fmac.c	Tue Oct 07 11:13:13 2008 -0400
+++ b/usr/src/uts/common/fmac/fmac.c	Tue Oct 07 11:13:46 2008 -0400
@@ -35,6 +35,7 @@
 #include <sys/param.h>
 #include <sys/kobj.h>
 #include <sys/vfs.h>
+#include <sys/acl.h>
 #include <sys/fmac/security.h>
 #include <sys/fmac/fmac.h>
 #include <sys/fmac/avc.h>
@@ -549,6 +550,17 @@
 	return (0);
 }
 
+#define	fmac_ace_to_av(mask, perm) \
+	if (mode & (mask)) { \
+		mode &= ~(mask); \
+		av |= (perm); \
+	} \
+
+#define	ACE_GETATTR_MASK (ACE_READ_NAMED_ATTRS | ACE_READ_ATTRIBUTES | \
+    ACE_READ_ACL)
+#define	ACE_SETATTR_MASK (ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ATTRIBUTES | \
+    ACE_WRITE_ACL | ACE_WRITE_OWNER)
+
 int
 fmac_vnode_access(vnode_t *vp, int mode, int flags, cred_t *cr,
     boolean_t audit)
@@ -568,17 +580,42 @@
 		return (0);
 
 	av = 0;
-	if (mode & VREAD)
-		av |= FILE__READ;
-	if (flags & V_APPEND)
-		av |= FILE__APPEND;
-	else if (mode & VWRITE)
-		av |= FILE__WRITE;
-	if (mode & VEXEC) {
-		if (sclass == SECCLASS_DIR)
-			av |= DIR__SEARCH;
-		else
-			av |= FILE__EXECUTE;
+
+	if (flags & V_ACE_MASK) {
+		mode &= ~ACE_SYNCHRONIZE; /* ignore synchronize bit */
+		fmac_ace_to_av(ACE_READ_DATA, FILE__READ);
+		fmac_ace_to_av(ACE_GETATTR_MASK, FILE__GETATTR);
+		fmac_ace_to_av(ACE_SETATTR_MASK, FILE__SETATTR);
+		if (sclass == SECCLASS_DIR) {
+			fmac_ace_to_av((ACE_ADD_FILE | ACE_ADD_SUBDIRECTORY),
+			    DIR__ADD_NAME);
+			fmac_ace_to_av(ACE_DELETE_CHILD, DIR__REMOVE_NAME);
+			fmac_ace_to_av(ACE_DELETE, DIR__RMDIR);
+			fmac_ace_to_av(ACE_EXECUTE, DIR__SEARCH);
+		} else {
+			fmac_ace_to_av(ACE_APPEND_DATA, FILE__APPEND);
+			fmac_ace_to_av(ACE_WRITE_DATA, FILE__WRITE);
+			fmac_ace_to_av(ACE_EXECUTE, FILE__EXECUTE);
+			fmac_ace_to_av(ACE_DELETE, FILE__UNLINK);
+		}
+		if (mode) {
+			cmn_err(CE_WARN, "FMAC:  Unknown ACE mask 0x%x\n",
+			    mode);
+			return (EACCES);
+		}
+	} else {
+		if (mode & VREAD)
+			av |= FILE__READ;
+		if (flags & V_APPEND)
+			av |= FILE__APPEND;
+		else if (mode & VWRITE)
+			av |= FILE__WRITE;
+		if (mode & VEXEC) {
+			if (sclass == SECCLASS_DIR)
+				av |= DIR__SEARCH;
+			else
+				av |= FILE__EXECUTE;
+		}
 	}
 
 	if (!av)
--- a/usr/src/uts/common/fs/vnode.c	Tue Oct 07 11:13:13 2008 -0400
+++ b/usr/src/uts/common/fs/vnode.c	Tue Oct 07 11:13:46 2008 -0400
@@ -3315,9 +3315,7 @@
 
 	err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct);
 	VOPSTATS_UPDATE(vp, access);
-	if (err)
-		return (err);
-	return (fmac_vnode_access(vp, mode, flags, cr, B_TRUE));
+	return (err);
 }
 
 int
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c	Tue Oct 07 11:13:13 2008 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c	Tue Oct 07 11:13:46 2008 -0400
@@ -42,6 +42,7 @@
 #include <sys/fs/zfs.h>
 #include <sys/mode.h>
 #include <sys/policy.h>
+#include <sys/fmac/fmac.h>
 #include <sys/zfs_znode.h>
 #include <sys/zfs_fuid.h>
 #include <sys/zfs_acl.h>
@@ -2353,11 +2354,8 @@
 	}
 
 	if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
-	    &check_privs, skipaclchk, cr)) == 0) {
-		if (is_attr)
-			VN_RELE(ZTOV(xzp));
-		return (0);
-	}
+	    &check_privs, skipaclchk, cr)) == 0)
+		goto out;
 
 	if (error && !check_privs) {
 		if (is_attr)
@@ -2424,6 +2422,11 @@
 		}
 	}
 
+out:
+	if (!error)
+		error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr,
+		    B_TRUE);
+
 	if (is_attr)
 		VN_RELE(ZTOV(xzp));
 
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c	Tue Oct 07 11:13:13 2008 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c	Tue Oct 07 11:13:46 2008 -0400
@@ -1333,10 +1333,6 @@
 			goto out;
 		}
 
-		error = fmac_vnode_access(ZTOV(zp), mode, aflags, cr, B_TRUE);
-		if (error)
-			goto out;
-
 		mutex_enter(&dzp->z_lock);
 		dzp->z_seq++;
 		mutex_exit(&dzp->z_lock);