瀏覽代碼

selinux: consider filesystem subtype in policies

Not considering sub filesystem has the following limitation. Support
for SELinux in FUSE is dependent on the particular userspace
filesystem, which is identified by the subtype. For e.g, GlusterFS,
a FUSE based filesystem supports SELinux (by mounting and processing
FUSE requests in different threads, avoiding the mount time
deadlock), whereas other FUSE based filesystems (identified by a
different subtype) have the mount time deadlock.

By considering the subtype of the filesytem in the SELinux policies,
allows us to specify a filesystem subtype, in the following way:

fs_use_xattr fuse.glusterfs gen_context(system_u:object_r:fs_t,s0);

This way not all FUSE filesystems are put in the same bucket and
subjected to the limitations of the other subtypes.

Signed-off-by: Anand Avati <avati@redhat.com>
Signed-off-by: Eric Paris <eparis@redhat.com>
Anand Avati 12 年之前
父節點
當前提交
102aefdda4
共有 2 個文件被更改,包括 60 次插入22 次删除
  1. 22 18
      security/selinux/hooks.c
  2. 38 4
      security/selinux/ss/services.c

+ 22 - 18
security/selinux/hooks.c

@@ -94,6 +94,10 @@
 #include "audit.h"
 #include "audit.h"
 #include "avc_ss.h"
 #include "avc_ss.h"
 
 
+#define SB_TYPE_FMT "%s%s%s"
+#define SB_SUBTYPE(sb) (sb->s_subtype && sb->s_subtype[0])
+#define SB_TYPE_ARGS(sb) sb->s_type->name, SB_SUBTYPE(sb) ? "." : "", SB_SUBTYPE(sb) ? sb->s_subtype : ""
+
 extern struct security_operations *security_ops;
 extern struct security_operations *security_ops;
 
 
 /* SECMARK reference count */
 /* SECMARK reference count */
@@ -407,8 +411,8 @@ static int sb_finish_set_opts(struct super_block *sb)
 		   the first boot of the SELinux kernel before we have
 		   the first boot of the SELinux kernel before we have
 		   assigned xattr values to the filesystem. */
 		   assigned xattr values to the filesystem. */
 		if (!root_inode->i_op->getxattr) {
 		if (!root_inode->i_op->getxattr) {
-			printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
-			       "xattr support\n", sb->s_id, sb->s_type->name);
+			printk(KERN_WARNING "SELinux: (dev %s, type "SB_TYPE_FMT") has no "
+			       "xattr support\n", sb->s_id, SB_TYPE_ARGS(sb));
 			rc = -EOPNOTSUPP;
 			rc = -EOPNOTSUPP;
 			goto out;
 			goto out;
 		}
 		}
@@ -416,22 +420,22 @@ static int sb_finish_set_opts(struct super_block *sb)
 		if (rc < 0 && rc != -ENODATA) {
 		if (rc < 0 && rc != -ENODATA) {
 			if (rc == -EOPNOTSUPP)
 			if (rc == -EOPNOTSUPP)
 				printk(KERN_WARNING "SELinux: (dev %s, type "
 				printk(KERN_WARNING "SELinux: (dev %s, type "
-				       "%s) has no security xattr handler\n",
-				       sb->s_id, sb->s_type->name);
+				       SB_TYPE_FMT") has no security xattr handler\n",
+				       sb->s_id, SB_TYPE_ARGS(sb));
 			else
 			else
 				printk(KERN_WARNING "SELinux: (dev %s, type "
 				printk(KERN_WARNING "SELinux: (dev %s, type "
-				       "%s) getxattr errno %d\n", sb->s_id,
-				       sb->s_type->name, -rc);
+				       SB_TYPE_FMT") getxattr errno %d\n", sb->s_id,
+				       SB_TYPE_ARGS(sb), -rc);
 			goto out;
 			goto out;
 		}
 		}
 	}
 	}
 
 
 	if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
 	if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
-		printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
-		       sb->s_id, sb->s_type->name);
+		printk(KERN_ERR "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), unknown behavior\n",
+		       sb->s_id, SB_TYPE_ARGS(sb));
 	else
 	else
-		printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
-		       sb->s_id, sb->s_type->name,
+		printk(KERN_DEBUG "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), %s\n",
+		       sb->s_id, SB_TYPE_ARGS(sb),
 		       labeling_behaviors[sbsec->behavior-1]);
 		       labeling_behaviors[sbsec->behavior-1]);
 
 
 	sbsec->flags |= SE_SBINITIALIZED;
 	sbsec->flags |= SE_SBINITIALIZED;
@@ -589,7 +593,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	const struct cred *cred = current_cred();
 	const struct cred *cred = current_cred();
 	int rc = 0, i;
 	int rc = 0, i;
 	struct superblock_security_struct *sbsec = sb->s_security;
 	struct superblock_security_struct *sbsec = sb->s_security;
-	const char *name = sb->s_type->name;
 	struct inode *inode = sbsec->sb->s_root->d_inode;
 	struct inode *inode = sbsec->sb->s_root->d_inode;
 	struct inode_security_struct *root_isec = inode->i_security;
 	struct inode_security_struct *root_isec = inode->i_security;
 	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
 	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
@@ -642,8 +645,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 					     strlen(mount_options[i]), &sid);
 					     strlen(mount_options[i]), &sid);
 		if (rc) {
 		if (rc) {
 			printk(KERN_WARNING "SELinux: security_context_to_sid"
 			printk(KERN_WARNING "SELinux: security_context_to_sid"
-			       "(%s) failed for (dev %s, type %s) errno=%d\n",
-			       mount_options[i], sb->s_id, name, rc);
+			       "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n",
+			       mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc);
 			goto out;
 			goto out;
 		}
 		}
 		switch (flags[i]) {
 		switch (flags[i]) {
@@ -779,7 +782,8 @@ out:
 out_double_mount:
 out_double_mount:
 	rc = -EINVAL;
 	rc = -EINVAL;
 	printk(KERN_WARNING "SELinux: mount invalid.  Same superblock, different "
 	printk(KERN_WARNING "SELinux: mount invalid.  Same superblock, different "
-	       "security settings for (dev %s, type %s)\n", sb->s_id, name);
+	       "security settings for (dev %s, type "SB_TYPE_FMT")\n", sb->s_id,
+	       SB_TYPE_ARGS(sb));
 	goto out;
 	goto out;
 }
 }
 
 
@@ -2439,8 +2443,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
 		rc = security_context_to_sid(mount_options[i], len, &sid);
 		rc = security_context_to_sid(mount_options[i], len, &sid);
 		if (rc) {
 		if (rc) {
 			printk(KERN_WARNING "SELinux: security_context_to_sid"
 			printk(KERN_WARNING "SELinux: security_context_to_sid"
-			       "(%s) failed for (dev %s, type %s) errno=%d\n",
-			       mount_options[i], sb->s_id, sb->s_type->name, rc);
+			       "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n",
+			       mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc);
 			goto out_free_opts;
 			goto out_free_opts;
 		}
 		}
 		rc = -EINVAL;
 		rc = -EINVAL;
@@ -2478,8 +2482,8 @@ out_free_secdata:
 	return rc;
 	return rc;
 out_bad_option:
 out_bad_option:
 	printk(KERN_WARNING "SELinux: unable to change security options "
 	printk(KERN_WARNING "SELinux: unable to change security options "
-	       "during remount (dev %s, type=%s)\n", sb->s_id,
-	       sb->s_type->name);
+	       "during remount (dev %s, type "SB_TYPE_FMT")\n", sb->s_id,
+	       SB_TYPE_ARGS(sb));
 	goto out_free_opts;
 	goto out_free_opts;
 }
 }
 
 

+ 38 - 4
security/selinux/ss/services.c

@@ -2334,16 +2334,50 @@ int security_fs_use(struct super_block *sb)
 	struct ocontext *c;
 	struct ocontext *c;
 	struct superblock_security_struct *sbsec = sb->s_security;
 	struct superblock_security_struct *sbsec = sb->s_security;
 	const char *fstype = sb->s_type->name;
 	const char *fstype = sb->s_type->name;
+	const char *subtype = (sb->s_subtype && sb->s_subtype[0]) ? sb->s_subtype : NULL;
+	struct ocontext *base = NULL;
 
 
 	read_lock(&policy_rwlock);
 	read_lock(&policy_rwlock);
 
 
-	c = policydb.ocontexts[OCON_FSUSE];
-	while (c) {
-		if (strcmp(fstype, c->u.name) == 0)
+	for (c = policydb.ocontexts[OCON_FSUSE]; c; c = c->next) {
+		char *sub;
+		int baselen;
+
+		baselen = strlen(fstype);
+
+		/* if base does not match, this is not the one */
+		if (strncmp(fstype, c->u.name, baselen))
+			continue;
+
+		/* if there is no subtype, this is the one! */
+		if (!subtype)
+			break;
+
+		/* skip past the base in this entry */
+		sub = c->u.name + baselen;
+
+		/* entry is only a base. save it. keep looking for subtype */
+		if (sub[0] == '\0') {
+			base = c;
+			continue;
+		}
+
+		/* entry is not followed by a subtype, so it is not a match */
+		if (sub[0] != '.')
+			continue;
+
+		/* whew, we found a subtype of this fstype */
+		sub++; /* move past '.' */
+
+		/* exact match of fstype AND subtype */
+		if (!strcmp(subtype, sub))
 			break;
 			break;
-		c = c->next;
 	}
 	}
 
 
+	/* in case we had found an fstype match but no subtype match */
+	if (!c)
+		c = base;
+
 	if (c) {
 	if (c) {
 		sbsec->behavior = c->v.behavior;
 		sbsec->behavior = c->v.behavior;
 		if (!c->sid[0]) {
 		if (!c->sid[0]) {