selinux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] selinux: support attributes in type transitions
@ 2019-05-06 13:12 Ondrej Mosnacek
  2019-05-06 20:59 ` Stephen Smalley
  0 siblings, 1 reply; 4+ messages in thread
From: Ondrej Mosnacek @ 2019-05-06 13:12 UTC (permalink / raw)
  To: selinux, Paul Moore
  Cc: Stephen Smalley, James Carter, Steve Lawrence, Petr Lautrbach

The amount of filename transition rules used in Fedora has grown a lot
due to many domains needing rules for correct /dev file labeling. This
has in turn caused the binary policy to increase in size a lot, too.

To mitigate this, start properly handling type attributes in type
transitions so that userspace can avoid always expanding them and
generate smaller policies. (Note: adding attribute support only for
named transition rules would be enough, but this patch adds it to all
type transition rules to keep better consistency.)

As an illustration, this change will reduce Fedora 31 binary policy from
~8.4 MiB to only ~2.8 MiB (~250K type transition rules to ~28K). These
numbers only take into account named file transition rules; the
reduction from basic type transition rules is likely going to be much
less radical.

The fact whether the kernel supports this feature is signaled to
userspace by an increment in policy version. With older policies the
transition computation is handled as before to avoid performance
regression.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---

Very mildly tested by applying a proof-of-concept patch against
libsepol [1], which disables type attribute expansion on src/target of
named file transition rules, and running the following on Fedora Rawhide
(from an unconfined root shell):

    mknod /dev/ram0 b 252 16
    ls -lZ /dev/ram0
    rm -f /dev/ram0

Without this patch, the corresponding transition rule (which happens to
have an attribute specified as the source type) didn't apply and the
file got label device_t (as expected). With this patch (+ the policy
version fallback condition disabled), the rule applied as it should and
the file got labeled correctly as fixed_disk_device_t.

We don't have a proper corresponding userspace patch yet, but I'd like
to have this patch out and get some feedback before moving on further.

See RHBZ 1660142 [2] for original discussion leading to this patch.

[1] https://github.com/WOnder93/selinux/commit/26283729657ec33b6743e929e1b5b40a54294043
[2] https://bugzilla.redhat.com/show_bug.cgi?id=1660142

 security/selinux/include/security.h |  33 +++---
 security/selinux/ss/services.c      | 177 ++++++++++++++++++++--------
 2 files changed, 147 insertions(+), 63 deletions(-)

diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 111121281c47..aa6b5a689cb7 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -22,28 +22,29 @@
 #define SECCLASS_NULL			0x0000 /* no class */
 
 /* Identify specific policy version changes */
-#define POLICYDB_VERSION_BASE		15
-#define POLICYDB_VERSION_BOOL		16
-#define POLICYDB_VERSION_IPV6		17
-#define POLICYDB_VERSION_NLCLASS	18
-#define POLICYDB_VERSION_VALIDATETRANS	19
-#define POLICYDB_VERSION_MLS		19
-#define POLICYDB_VERSION_AVTAB		20
-#define POLICYDB_VERSION_RANGETRANS	21
-#define POLICYDB_VERSION_POLCAP		22
-#define POLICYDB_VERSION_PERMISSIVE	23
-#define POLICYDB_VERSION_BOUNDARY	24
-#define POLICYDB_VERSION_FILENAME_TRANS	25
-#define POLICYDB_VERSION_ROLETRANS	26
+#define POLICYDB_VERSION_BASE			15
+#define POLICYDB_VERSION_BOOL			16
+#define POLICYDB_VERSION_IPV6			17
+#define POLICYDB_VERSION_NLCLASS		18
+#define POLICYDB_VERSION_VALIDATETRANS		19
+#define POLICYDB_VERSION_MLS			19
+#define POLICYDB_VERSION_AVTAB			20
+#define POLICYDB_VERSION_RANGETRANS		21
+#define POLICYDB_VERSION_POLCAP			22
+#define POLICYDB_VERSION_PERMISSIVE		23
+#define POLICYDB_VERSION_BOUNDARY		24
+#define POLICYDB_VERSION_FILENAME_TRANS		25
+#define POLICYDB_VERSION_ROLETRANS		26
 #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS	27
-#define POLICYDB_VERSION_DEFAULT_TYPE	28
+#define POLICYDB_VERSION_DEFAULT_TYPE		28
 #define POLICYDB_VERSION_CONSTRAINT_NAMES	29
-#define POLICYDB_VERSION_XPERMS_IOCTL	30
+#define POLICYDB_VERSION_XPERMS_IOCTL		30
 #define POLICYDB_VERSION_INFINIBAND		31
+#define POLICYDB_VERSION_TYPE_TRANS_ATTR	32
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_INFINIBAND
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_TYPE_TRANS_ATTR
 
 /* Mask for just the mount related flags */
 #define SE_MNTMASK	0x0f
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index cc043bc8fd4c..1e8293201184 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1610,30 +1610,137 @@ out:
 	return -EACCES;
 }
 
-static void filename_compute_type(struct policydb *policydb,
-				  struct context *newcontext,
-				  u32 stype, u32 ttype, u16 tclass,
-				  const char *objname)
+static void compute_type_noattr(struct policydb *policydb,
+				struct context *newcontext,
+				u32 stype, u32 ttype,
+				u16 tclass, u32 specified,
+				const char *objname)
 {
-	struct filename_trans ft;
-	struct filename_trans_datum *otype;
+	struct avtab_key avkey;
+	struct avtab_datum *avdatum = NULL;
+	struct avtab_node *node;
 
 	/*
-	 * Most filename trans rules are going to live in specific directories
-	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
-	 * if the ttype does not contain any rules.
+	 * if we have a objname this is a file trans check so check those
+	 * rules
 	 */
-	if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
+	if (objname) {
+		struct filename_trans ft;
+		struct filename_trans_datum *otype;
+
+		/*
+		 * Most filename trans rules are going to live in specific
+		 * directories like /dev or /var/run.  This bitmap will quickly
+		 * skip rule searches if the ttype does not contain any rules.
+		 */
+		if (ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype)) {
+			ft.stype = stype;
+			ft.ttype = ttype;
+			ft.tclass = tclass;
+			ft.name = objname;
+
+			otype = hashtab_search(policydb->filename_trans, &ft);
+			if (otype) {
+				newcontext->type = otype->otype;
+				return;
+			}
+		}
+	}
+
+	/* Look for a type transition/member/change rule. */
+	avkey.source_type = stype;
+	avkey.target_type = ttype;
+	avkey.target_class = tclass;
+	avkey.specified = specified;
+	avdatum = avtab_search(&policydb->te_avtab, &avkey);
+	if (avdatum) {
+		newcontext->type = avdatum->u.data;
 		return;
+	}
+
+	/* If no permanent rule, also check for enabled conditional rules */
+	node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
+	for (; node; node = avtab_search_node_next(node, specified)) {
+		if (node->key.specified & AVTAB_ENABLED) {
+			newcontext->type = node->datum.u.data;
+			return;
+		}
+	}
+}
 
-	ft.stype = stype;
-	ft.ttype = ttype;
-	ft.tclass = tclass;
-	ft.name = objname;
+static void compute_type(struct policydb *policydb, struct context *newcontext,
+			 u32 stype, u32 ttype, u16 tclass, u32 specified,
+			 const char *objname)
+{
+	struct avtab_key avkey;
+	struct avtab_datum *avdatum = NULL;
+	struct avtab_node *node;
+	struct ebitmap *sattr, *tattr;
+	struct ebitmap_node *snode, *tnode;
+	unsigned int i, j;
+
+	sattr = &policydb->type_attr_map_array[stype - 1];
+	tattr = &policydb->type_attr_map_array[ttype - 1];
+
+	if (objname) {
+		struct filename_trans ft;
+		struct filename_trans_datum *otype;
+
+		ebitmap_for_each_positive_bit(tattr, tnode, j) {
+			/*
+			 * Most filename trans rules are going to live in
+			 * specific directories like /dev or /var/run.  This
+			 * bitmap will quickly skip rule searches if the ttype
+			 * does not contain any rules.
+			 */
+			if (!ebitmap_get_bit(&policydb->filename_trans_ttypes,
+					     j + 1))
+				continue;
 
-	otype = hashtab_search(policydb->filename_trans, &ft);
-	if (otype)
-		newcontext->type = otype->otype;
+			ebitmap_for_each_positive_bit(sattr, snode, i) {
+				ft.stype = i + 1;
+				ft.ttype = j + 1;
+				ft.tclass = tclass;
+				ft.name = objname;
+
+				otype = hashtab_search(policydb->filename_trans,
+						       &ft);
+				if (otype) {
+					newcontext->type = otype->otype;
+					return;
+				}
+			}
+		}
+	}
+
+	/* Look for a type transition/member/change rule. */
+	avkey.target_class = tclass;
+	avkey.specified = specified;
+	ebitmap_for_each_positive_bit(sattr, snode, i) {
+		ebitmap_for_each_positive_bit(tattr, tnode, j) {
+			avkey.source_type = i + 1;
+			avkey.target_type = j + 1;
+			avdatum = avtab_search(&policydb->te_avtab, &avkey);
+			if (avdatum) {
+				newcontext->type = avdatum->u.data;
+				return;
+			}
+
+			/*
+			 * If no permanent rule, also check for enabled
+			 * conditional rules
+			 */
+			node = avtab_search_node(&policydb->te_cond_avtab,
+						 &avkey);
+			for (; node;
+			     node = avtab_search_node_next(node, specified)) {
+				if (node->key.specified & AVTAB_ENABLED) {
+					newcontext->type = node->datum.u.data;
+					return;
+				}
+			}
+		}
+	}
 }
 
 static int security_compute_sid(struct selinux_state *state,
@@ -1650,9 +1757,6 @@ static int security_compute_sid(struct selinux_state *state,
 	struct class_datum *cladatum = NULL;
 	struct context *scontext = NULL, *tcontext = NULL, newcontext;
 	struct role_trans *roletr = NULL;
-	struct avtab_key avkey;
-	struct avtab_datum *avdatum;
-	struct avtab_node *node;
 	u16 tclass;
 	int rc = 0;
 	bool sock;
@@ -1748,33 +1852,12 @@ static int security_compute_sid(struct selinux_state *state,
 		}
 	}
 
-	/* Look for a type transition/member/change rule. */
-	avkey.source_type = scontext->type;
-	avkey.target_type = tcontext->type;
-	avkey.target_class = tclass;
-	avkey.specified = specified;
-	avdatum = avtab_search(&policydb->te_avtab, &avkey);
-
-	/* If no permanent rule, also check for enabled conditional rules */
-	if (!avdatum) {
-		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
-		for (; node; node = avtab_search_node_next(node, specified)) {
-			if (node->key.specified & AVTAB_ENABLED) {
-				avdatum = &node->datum;
-				break;
-			}
-		}
-	}
-
-	if (avdatum) {
-		/* Use the type from the type transition/member/change rule. */
-		newcontext.type = avdatum->u.data;
-	}
-
-	/* if we have a objname this is a file trans check so check those rules */
-	if (objname)
-		filename_compute_type(policydb, &newcontext, scontext->type,
-				      tcontext->type, tclass, objname);
+	if (policydb->policyvers < POLICYDB_VERSION_TYPE_TRANS_ATTR)
+		compute_type_noattr(policydb, &newcontext, scontext->type,
+				    tcontext->type, tclass, specified, objname);
+	else
+		compute_type(policydb, &newcontext, scontext->type,
+			     tcontext->type, tclass, specified, objname);
 
 	/* Check for class-specific changes. */
 	if (specified & AVTAB_TRANSITION) {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-05-13 13:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-06 13:12 [PATCH] selinux: support attributes in type transitions Ondrej Mosnacek
2019-05-06 20:59 ` Stephen Smalley
2019-05-13 11:16   ` Ondrej Mosnacek
2019-05-13 13:18     ` Stephen Smalley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).