All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 1/4] libsepol: refactor ebitmap conversion in link.c
@ 2022-06-16 13:14 Christian Göttsche
  2022-06-16 13:14 ` [RFC PATCH 2/4] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Christian Göttsche @ 2022-06-16 13:14 UTC (permalink / raw)
  To: selinux

Refactor the ebitmap conversions in link.c into its own function.

Do not log an OOM message twice on type_set_or_convert() failure.

Drop the now unused state parameter from type_set_or_convert() and
type_set_convert().

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libsepol/src/link.c | 140 +++++++++++++++-----------------------------
 1 file changed, 47 insertions(+), 93 deletions(-)

diff --git a/libsepol/src/link.c b/libsepol/src/link.c
index 7e8313cb..cbe4cea4 100644
--- a/libsepol/src/link.c
+++ b/libsepol/src/link.c
@@ -958,26 +958,28 @@ static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 
 /*********** callbacks that fix bitmaps ***********/
 
-static int type_set_convert(type_set_t * types, type_set_t * dst,
-			    policy_module_t * mod, link_state_t * state
-			    __attribute__ ((unused)))
+static int ebitmap_convert(const ebitmap_t *src, ebitmap_t *dst, const uint32_t *map)
 {
-	unsigned int i;
-	ebitmap_node_t *tnode;
-	ebitmap_for_each_positive_bit(&types->types, tnode, i) {
-		assert(mod->map[SYM_TYPES][i]);
-		if (ebitmap_set_bit
-		    (&dst->types, mod->map[SYM_TYPES][i] - 1, 1)) {
-			goto cleanup;
-		}
-	}
-	ebitmap_for_each_positive_bit(&types->negset, tnode, i) {
-		assert(mod->map[SYM_TYPES][i]);
-		if (ebitmap_set_bit
-		    (&dst->negset, mod->map[SYM_TYPES][i] - 1, 1)) {
-			goto cleanup;
-		}
+	unsigned int bit;
+	ebitmap_node_t *node;
+	ebitmap_for_each_positive_bit(src, node, bit) {
+		assert(map[bit]);
+		if (ebitmap_set_bit(dst, map[bit] - 1, 1))
+			return -1;
 	}
+
+	return 0;
+}
+
+static int type_set_convert(const type_set_t * types, type_set_t * dst,
+			    const policy_module_t * mod)
+{
+	if (ebitmap_convert(&types->types, &dst->types, mod->map[SYM_TYPES]))
+		goto cleanup;
+
+	if (ebitmap_convert(&types->negset, &dst->negset, mod->map[SYM_TYPES]))
+		goto cleanup;
+
 	dst->flags = types->flags;
 	return 0;
 
@@ -988,13 +990,13 @@ static int type_set_convert(type_set_t * types, type_set_t * dst,
 /* OR 2 typemaps together and at the same time map the src types to
  * the correct values in the dst typeset.
  */
-static int type_set_or_convert(type_set_t * types, type_set_t * dst,
-			       policy_module_t * mod, link_state_t * state)
+static int type_set_or_convert(const type_set_t * types, type_set_t * dst,
+			       const policy_module_t * mod)
 {
 	type_set_t ts_tmp;
 
 	type_set_init(&ts_tmp);
-	if (type_set_convert(types, &ts_tmp, mod, state) == -1) {
+	if (type_set_convert(types, &ts_tmp, mod) == -1) {
 		goto cleanup;
 	}
 	if (type_set_or_eq(dst, &ts_tmp)) {
@@ -1004,7 +1006,6 @@ static int type_set_or_convert(type_set_t * types, type_set_t * dst,
 	return 0;
 
       cleanup:
-	ERR(state->handle, "Out of memory!");
 	type_set_destroy(&ts_tmp);
 	return -1;
 }
@@ -1012,18 +1013,11 @@ static int type_set_or_convert(type_set_t * types, type_set_t * dst,
 static int role_set_or_convert(role_set_t * roles, role_set_t * dst,
 			       policy_module_t * mod, link_state_t * state)
 {
-	unsigned int i;
 	ebitmap_t tmp;
-	ebitmap_node_t *rnode;
 
 	ebitmap_init(&tmp);
-	ebitmap_for_each_positive_bit(&roles->roles, rnode, i) {
-		assert(mod->map[SYM_ROLES][i]);
-		if (ebitmap_set_bit
-		    (&tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
-			goto cleanup;
-		}
-	}
+	if (ebitmap_convert(&roles->roles, &tmp, mod->map[SYM_ROLES]))
+		goto cleanup;
 	if (ebitmap_union(&dst->roles, &tmp)) {
 		goto cleanup;
 	}
@@ -1088,13 +1082,11 @@ static int mls_range_convert(mls_semantic_range_t * src, mls_semantic_range_t *
 static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
 			     void *data)
 {
-	unsigned int i;
 	char *id = key;
 	role_datum_t *role, *dest_role = NULL;
 	link_state_t *state = (link_state_t *) data;
 	ebitmap_t e_tmp;
 	policy_module_t *mod = state->cur;
-	ebitmap_node_t *rnode;
 	hashtab_t role_tab;
 
 	role = (role_datum_t *) datum;
@@ -1111,30 +1103,20 @@ static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
 	}
 
 	ebitmap_init(&e_tmp);
-	ebitmap_for_each_positive_bit(&role->dominates, rnode, i) {
-		assert(mod->map[SYM_ROLES][i]);
-		if (ebitmap_set_bit
-		    (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
-			goto cleanup;
-		}
-	}
+	if (ebitmap_convert(&role->dominates, &e_tmp, mod->map[SYM_ROLES]))
+		goto cleanup;
 	if (ebitmap_union(&dest_role->dominates, &e_tmp)) {
 		goto cleanup;
 	}
-	if (type_set_or_convert(&role->types, &dest_role->types, mod, state)) {
+	if (type_set_or_convert(&role->types, &dest_role->types, mod)) {
 		goto cleanup;
 	}
 	ebitmap_destroy(&e_tmp);
 	
 	if (role->flavor == ROLE_ATTRIB) {
 		ebitmap_init(&e_tmp);
-		ebitmap_for_each_positive_bit(&role->roles, rnode, i) {
-			assert(mod->map[SYM_ROLES][i]);
-			if (ebitmap_set_bit
-			    (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
-				goto cleanup;
-			}
-		}
+		if (ebitmap_convert(&role->roles, &e_tmp, mod->map[SYM_ROLES]))
+			goto cleanup;
 		if (ebitmap_union(&dest_role->roles, &e_tmp)) {
 			goto cleanup;
 		}
@@ -1152,13 +1134,11 @@ static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
 static int type_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
 			     void *data)
 {
-	unsigned int i;
 	char *id = key;
 	type_datum_t *type, *new_type = NULL;
 	link_state_t *state = (link_state_t *) data;
 	ebitmap_t e_tmp;
 	policy_module_t *mod = state->cur;
-	ebitmap_node_t *tnode;
 	symtab_t *typetab;
 
 	type = (type_datum_t *) datum;
@@ -1181,13 +1161,8 @@ static int type_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
 	}
 
 	ebitmap_init(&e_tmp);
-	ebitmap_for_each_positive_bit(&type->types, tnode, i) {
-		assert(mod->map[SYM_TYPES][i]);
-		if (ebitmap_set_bit
-		    (&e_tmp, mod->map[SYM_TYPES][i] - 1, 1)) {
-			goto cleanup;
-		}
-	}
+	if (ebitmap_convert(&type->types, &e_tmp, mod->map[SYM_TYPES]))
+		goto cleanup;
 	if (ebitmap_union(&new_type->types, &e_tmp)) {
 		goto cleanup;
 	}
@@ -1269,9 +1244,8 @@ static int copy_avrule_list(avrule_t * list, avrule_t ** dst,
 		new_rule->specified = cur->specified;
 		new_rule->flags = cur->flags;
 		if (type_set_convert
-		    (&cur->stypes, &new_rule->stypes, module, state) == -1
-		    || type_set_convert(&cur->ttypes, &new_rule->ttypes, module,
-					state) == -1) {
+		    (&cur->stypes, &new_rule->stypes, module) == -1
+		    || type_set_convert(&cur->ttypes, &new_rule->ttypes, module) == -1) {
 			goto cleanup;
 		}
 
@@ -1355,8 +1329,6 @@ static int copy_role_trans_list(role_trans_rule_t * list,
 				policy_module_t * module, link_state_t * state)
 {
 	role_trans_rule_t *cur, *new_rule = NULL, *tail;
-	unsigned int i;
-	ebitmap_node_t *cnode;
 
 	cur = list;
 	tail = *dst;
@@ -1374,19 +1346,12 @@ static int copy_role_trans_list(role_trans_rule_t * list,
 		if (role_set_or_convert
 		    (&cur->roles, &new_rule->roles, module, state)
 		    || type_set_or_convert(&cur->types, &new_rule->types,
-					   module, state)) {
+					   module)) {
 			goto cleanup;
 		}
 
-		ebitmap_for_each_positive_bit(&cur->classes, cnode, i) {
-			assert(module->map[SYM_CLASSES][i]);
-			if (ebitmap_set_bit(&new_rule->classes,
-					    module->
-					    map[SYM_CLASSES][i] - 1,
-					    1)) {
-				goto cleanup;
-			}
-		}
+		if (ebitmap_convert(&cur->classes, &new_rule->classes, module->map[SYM_CLASSES]))
+			goto cleanup;
 
 		new_rule->new_role = module->map[SYM_ROLES][cur->new_role - 1];
 
@@ -1476,8 +1441,8 @@ static int copy_filename_trans_list(filename_trans_rule_t * list,
 		if (!new_rule->name)
 			goto err;
 
-		if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module, state) ||
-		    type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module, state))
+		if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module) ||
+		    type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module))
 			goto err;
 
 		new_rule->tclass = module->map[SYM_CLASSES][cur->tclass - 1];
@@ -1497,8 +1462,6 @@ static int copy_range_trans_list(range_trans_rule_t * rules,
 				 policy_module_t * mod, link_state_t * state)
 {
 	range_trans_rule_t *rule, *new_rule = NULL;
-	unsigned int i;
-	ebitmap_node_t *cnode;
 
 	for (rule = rules; rule; rule = rule->next) {
 		new_rule =
@@ -1512,21 +1475,15 @@ static int copy_range_trans_list(range_trans_rule_t * rules,
 		*dst = new_rule;
 
 		if (type_set_convert(&rule->stypes, &new_rule->stypes,
-				     mod, state))
+				     mod))
 			goto cleanup;
 
 		if (type_set_convert(&rule->ttypes, &new_rule->ttypes,
-				     mod, state))
+				     mod))
 			goto cleanup;
 
-		ebitmap_for_each_positive_bit(&rule->tclasses, cnode, i) {
-			assert(mod->map[SYM_CLASSES][i]);
-			if (ebitmap_set_bit
-			    (&new_rule->tclasses,
-			     mod->map[SYM_CLASSES][i] - 1, 1)) {
-				goto cleanup;
-			}
-		}
+		if (ebitmap_convert(&rule->tclasses, &new_rule->tclasses, mod->map[SYM_CLASSES]))
+			goto cleanup;
 
 		if (mls_range_convert(&rule->trange, &new_rule->trange, mod, state))
 			goto cleanup;
@@ -1688,15 +1645,12 @@ static int copy_scope_index(scope_index_t * src, scope_index_t * dest,
 	}
 	dest->class_perms_len = largest_mapped_class_value;
 	for (i = 0; i < src->class_perms_len; i++) {
-		ebitmap_t *srcmap = src->class_perms_map + i;
+		const ebitmap_t *srcmap = src->class_perms_map + i;
 		ebitmap_t *destmap =
 		    dest->class_perms_map + module->map[SYM_CLASSES][i] - 1;
-		ebitmap_for_each_positive_bit(srcmap, node, j) {
-			if (ebitmap_set_bit(destmap, module->perm_map[i][j] - 1,
-					    1)) {
-				goto cleanup;
-			}
-		}
+
+		if (ebitmap_convert(srcmap, destmap, module->perm_map[i]))
+			goto cleanup;
 	}
 
 	return 0;
-- 
2.36.1


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

* [RFC PATCH 2/4] libsepol: add ebitmap iterator wrapper with startnode
  2022-06-16 13:14 [RFC PATCH 1/4] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
@ 2022-06-16 13:14 ` Christian Göttsche
  2022-06-28 22:01   ` Nicolas Iooss
  2022-06-16 13:14 ` [RFC PATCH 3/4] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
  2022-06-16 13:14 ` [RFC PATCH 4/4] checkpolicy: add front-end support for segregate attributes Christian Göttsche
  2 siblings, 1 reply; 6+ messages in thread
From: Christian Göttsche @ 2022-06-16 13:14 UTC (permalink / raw)
  To: selinux

Similar like ebitmap_for_each_bit() iterates over all bits of an ebitmap
add ebitmap_for_each_bit_starting() iterating over all bits starting
from a specific node and bit, which can be from an outer iteration.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libsepol/include/sepol/policydb/ebitmap.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/libsepol/include/sepol/policydb/ebitmap.h b/libsepol/include/sepol/policydb/ebitmap.h
index 81d0c7a6..83ff54c2 100644
--- a/libsepol/include/sepol/policydb/ebitmap.h
+++ b/libsepol/include/sepol/policydb/ebitmap.h
@@ -80,6 +80,13 @@ static inline int ebitmap_node_get_bit(const ebitmap_node_t * n, unsigned int bi
 #define ebitmap_for_each_positive_bit(e, n, bit) \
 	ebitmap_for_each_bit(e, n, bit) if (ebitmap_node_get_bit(n, bit)) \
 
+#define ebitmap_for_each_bit_starting(e, startnode, startbit, n, bit) \
+	n = startnode; \
+	for (bit = ebitmap_next(&n, startbit); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
+#define ebitmap_for_each_positive_bit_starting(e, startnode, startbit, n, bit) \
+	ebitmap_for_each_bit_starting(e, startnode, startbit, n, bit) if (ebitmap_node_get_bit(n, bit)) \
+
 extern int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2);
 extern int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2);
 extern int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1);
-- 
2.36.1


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

* [RFC PATCH 3/4] libsepol: add compile-time constraint for mutual exclusive attributes
  2022-06-16 13:14 [RFC PATCH 1/4] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
  2022-06-16 13:14 ` [RFC PATCH 2/4] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
@ 2022-06-16 13:14 ` Christian Göttsche
  2022-06-28 21:54   ` Nicolas Iooss
  2022-06-16 13:14 ` [RFC PATCH 4/4] checkpolicy: add front-end support for segregate attributes Christian Göttsche
  2 siblings, 1 reply; 6+ messages in thread
From: Christian Göttsche @ 2022-06-16 13:14 UTC (permalink / raw)
  To: selinux

Add a new compile-time constraint, similar to neverallow, which enables
to specify two or more type attributes to be mutual exclusive.  This
means no type can be associated with more than one of them.

The constraints are stored as a linked-list in the policy for modular
policies, by a new modular policy version, and are discarded in kernel
policies, not needing any kernel support.

Some Reference Policy examples:

    unpriv_userdomain, admindomain:

        <no violations>

    client_packet_type, server_packet_type:

        <no violations>

    auth_file_type, non_auth_file_type:

        <no violations>

    pseudofs, xattrfs, noxattrfs:

         <no violations>

    reserved_port_type, unreserved_port_type:

         <no violations>

    security_file_type, non_security_file_type:

        libsepol.check_segregate_attributes: segregate_attributes violated by type dnssec_t associated with attributes security_file_type and non_security_file_type

    ibendport_type, packet_type, sysctl_type, device_node, ibpkey_type,
    sysfs_types, domain, boolean_type, netif_type, file_type, node_type,
    proc_type, port_type:

        libsepol.check_segregate_attributes: segregate_attributes violated by type virt_content_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type sysctl_fs_t associated with attributes sysctl_type and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type initrc_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type qemu_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type user_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type dockerc_t associated with attributes domain and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type cpu_online_t associated with attributes sysfs_types and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type cardmgr_dev_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type sysctl_t associated with attributes sysctl_type and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type bootloader_tmp_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type xen_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type svirt_prot_exec_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type xen_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type proc_t associated with attributes file_type and proc_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type sysfs_t associated with attributes sysfs_types and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type proc_xen_t associated with attributes file_type and proc_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type svirt_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type virt_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: segregate_attributes violated by type container_file_t associated with attributes device_node and file_type

    libsepol.check_assertions: 20 segregate attribute failures occurred

Closes: https://github.com/SELinuxProject/selinux/issues/42

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libsepol/include/sepol/policydb/policydb.h | 18 +++++-
 libsepol/src/assertion.c                   | 59 ++++++++++++++++-
 libsepol/src/expand.c                      | 56 +++++++++++++++-
 libsepol/src/link.c                        | 57 ++++++++++++++++
 libsepol/src/policydb.c                    | 75 ++++++++++++++++++++++
 libsepol/src/policydb_validate.c           | 29 +++++++++
 libsepol/src/write.c                       | 34 +++++++++-
 7 files changed, 323 insertions(+), 5 deletions(-)

diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index de0068a6..b4a78e2f 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -192,6 +192,16 @@ typedef struct type_datum {
 	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/* Mutual exclusive attributes */
+typedef struct segregate_attribute {
+	ebitmap_t attrs;	/* mutual exclusive attributes */
+	unsigned long line;	/* line number from policy.conf where this rule originated  */
+	/* source file name and line number (e.g. .te file) */
+	char *source_filename;
+	unsigned long source_line;
+	struct segregate_attribute *next;
+} segregate_attribute_t;
+
 /*
  * Properties of type_datum
  * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
@@ -605,6 +615,9 @@ typedef struct policydb {
 	   bitmaps.  Someday the 0 bit may be used for global permissive */
 	ebitmap_t permissive_map;
 
+	/* mutual exclusive attributes (not preserved in kernel policy) */
+	segregate_attribute_t *segregate_attributes;
+
 	unsigned policyvers;
 
 	unsigned handle_unknown;
@@ -696,6 +709,8 @@ extern void level_datum_init(level_datum_t * x);
 extern void level_datum_destroy(level_datum_t * x);
 extern void cat_datum_init(cat_datum_t * x);
 extern void cat_datum_destroy(cat_datum_t * x);
+extern void segregate_attribute_init(segregate_attribute_t * x);
+extern void segregate_attribute_destroy(segregate_attribute_t * x);
 extern int check_assertion(policydb_t *p, avrule_t *avrule);
 extern int check_assertions(sepol_handle_t * handle,
 			    policydb_t * p, avrule_t * avrules);
@@ -783,9 +798,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
 #define MOD_POLICYDB_VERSION_INFINIBAND		19
 #define MOD_POLICYDB_VERSION_GLBLUB		20
 #define MOD_POLICYDB_VERSION_SELF_TYPETRANS	21
+#define MOD_POLICYDB_VERSION_SEGREGATEATTRIBUTE	22
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_SELF_TYPETRANS
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_SEGREGATEATTRIBUTE
 
 #define POLICYDB_CONFIG_MLS    1
 
diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c
index 161874c3..28a9c55f 100644
--- a/libsepol/src/assertion.c
+++ b/libsepol/src/assertion.c
@@ -36,7 +36,7 @@ struct avtab_match_args {
 	unsigned long errors;
 };
 
-static const char* policy_name(policydb_t *p) {
+static const char* policy_name(const policydb_t *p) {
 	const char *policy_file = "policy.conf";
 	if (p->name) {
 		policy_file = p->name;
@@ -535,6 +535,53 @@ int check_assertion(policydb_t *p, avrule_t *avrule)
 	return rc;
 }
 
+static int check_segregate_attributes(sepol_handle_t *handle, const policydb_t *p)
+{
+	int errors = 0;
+	const segregate_attribute_t *sattr;
+
+	for (sattr = p->segregate_attributes; sattr; sattr = sattr->next) {
+		ebitmap_node_t *first_node;
+		unsigned int first_bit;
+
+		ebitmap_for_each_positive_bit(&sattr->attrs, first_node, first_bit) {
+			ebitmap_node_t *second_node;
+			unsigned int second_bit;
+
+			ebitmap_for_each_positive_bit_starting(&sattr->attrs, first_node, first_bit, second_node, second_bit) {
+				ebitmap_t attr_union;
+				ebitmap_node_t *type_node;
+				unsigned int type_bit;
+
+				if (ebitmap_and(&attr_union, &p->attr_type_map[first_bit], &p->attr_type_map[second_bit]))
+					return -1;
+
+				ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) {
+					if (sattr->source_filename)
+						ERR(handle, "segregate_attributes on line %lu of %s (or line %lu of %s) violated by "
+							"type %s associated with attributes %s and %s",
+							sattr->source_line, sattr->source_filename, sattr->line, policy_name(p),
+							p->p_type_val_to_name[type_bit], p->p_type_val_to_name[first_bit], p->p_type_val_to_name[second_bit]);
+					else if (sattr->line)
+						ERR(handle, "segregate_attributes on line %lu of %s violated by "
+							"type %s associated with attributes %s and %s",
+							sattr->line, policy_name(p),
+							p->p_type_val_to_name[type_bit], p->p_type_val_to_name[first_bit], p->p_type_val_to_name[second_bit]);
+					else
+						ERR(handle, "segregate_attributes violated by "
+							"type %s associated with attributes %s and %s",
+							p->p_type_val_to_name[type_bit], p->p_type_val_to_name[first_bit], p->p_type_val_to_name[second_bit]);
+					errors++;
+				}
+
+				ebitmap_destroy(&attr_union);
+			}
+		}
+	}
+
+	return errors;
+}
+
 int check_assertions(sepol_handle_t * handle, policydb_t * p,
 		     avrule_t * avrules)
 {
@@ -570,5 +617,15 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
 	if (errors)
 		ERR(handle, "%lu neverallow failures occurred", errors);
 
+	rc = check_segregate_attributes(handle, p);
+	if (rc < 0) {
+		ERR(handle, "Error occurred while checking segregate attributes");
+		return -1;
+	}
+	if (rc) {
+		ERR(handle, "%d segregate attribute failures occurred", rc);
+		errors += rc;
+	}
+
 	return errors ? -1 : 0;
 }
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index 8d19850e..483f6905 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -56,7 +56,7 @@ static void expand_state_init(expand_state_t * state)
 	memset(state, 0, sizeof(expand_state_t));
 }
 
-static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map)
+static int map_ebitmap(const ebitmap_t * src, ebitmap_t * dst, const uint32_t * map)
 {
 	unsigned int i;
 	ebitmap_node_t *tnode;
@@ -2341,6 +2341,56 @@ static int genfs_copy(expand_state_t * state)
 	return 0;
 }
 
+static int segregate_attribute_copy(expand_state_t *state)
+{
+	const segregate_attribute_t *old;
+	segregate_attribute_t *list = NULL;
+
+	for (old = state->base->segregate_attributes; old; old = old->next) {
+		segregate_attribute_t *new;
+
+		new = calloc(1, sizeof(segregate_attribute_t));
+		if (!new) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		new->next = NULL;
+		new->line = old->line;
+		new->source_line = old->source_line;
+		if (old->source_filename) {
+			new->source_filename = strdup(old->source_filename);
+			if (!new->source_filename) {
+				ERR(state->handle, "Out of memory!");
+				free(new);
+				return -1;
+			}
+		}
+
+		if (map_ebitmap(&old->attrs, &new->attrs, state->typemap)) {
+			ERR(state->handle, "out of memory");
+			ebitmap_destroy(&new->attrs);
+			free(new->source_filename);
+			free(new);
+			return -1;
+		}
+
+		if (list)
+			list->next = new;
+		else {
+			if (state->out->segregate_attributes) {
+				segregate_attribute_t *s;
+				for (s = state->out->segregate_attributes; s->next; s = s->next) {}
+				s->next = new;
+			} else
+				state->out->segregate_attributes = new;
+		}
+		list = new;
+	}
+
+	return 0;
+}
+
 static int type_attr_map(hashtab_key_t key
 			 __attribute__ ((unused)), hashtab_datum_t datum,
 			 void *ptr)
@@ -3173,6 +3223,10 @@ int expand_module(sepol_handle_t * handle,
 	if (genfs_copy(&state))
 		goto cleanup;
 
+	/* copy segregate attributes */
+	if (segregate_attribute_copy(&state))
+		goto cleanup;
+
 	/* Build the type<->attribute maps and remove attributes. */
 	state.out->attr_type_map = calloc(state.out->p_types.nprim,
 					  sizeof(ebitmap_t));
diff --git a/libsepol/src/link.c b/libsepol/src/link.c
index cbe4cea4..04f8b2cf 100644
--- a/libsepol/src/link.c
+++ b/libsepol/src/link.c
@@ -1857,6 +1857,58 @@ static int scope_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 	return -1;
 }
 
+static int copy_segregate_attributes(link_state_t * state, const policy_module_t *module)
+{
+	const segregate_attribute_t *src_sattr;
+	segregate_attribute_t *list = NULL;
+
+	for (src_sattr = module->policy->segregate_attributes; src_sattr; src_sattr = src_sattr->next) {
+		segregate_attribute_t *new_sattr;
+
+		new_sattr = calloc(1, sizeof(segregate_attribute_t));
+		if (!new_sattr) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		ebitmap_init(&new_sattr->attrs);
+		if (ebitmap_convert(&src_sattr->attrs, &new_sattr->attrs, module->map[SYM_TYPES])) {
+			ebitmap_destroy(&new_sattr->attrs);
+			free(new_sattr);
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		new_sattr->line = src_sattr->line;
+
+		if (src_sattr->source_filename) {
+			new_sattr->source_filename = strdup(src_sattr->source_filename);
+			if (!new_sattr->source_filename) {
+				ebitmap_destroy(&new_sattr->attrs);
+				free(new_sattr);
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+		}
+
+		new_sattr->source_line = src_sattr->source_line;
+
+		if (list)
+			list->next = new_sattr;
+		else {
+			if (state->base->segregate_attributes) {
+				segregate_attribute_t *s;
+				for (s = state->base->segregate_attributes; s->next; s = s->next) {}
+				s->next = new_sattr;
+			} else
+				state->base->segregate_attributes = new_sattr;
+		}
+		list = new_sattr;
+	}
+
+	return 0;
+}
+
 /* Copy a module over to a base, remapping all values within.  After
  * all identifiers and rules are done, copy the scoping information.
  * This is when it checks for duplicate declarations. */
@@ -1891,6 +1943,11 @@ static int copy_module(link_state_t * state, policy_module_t * module)
 		}
 	}
 
+	ret = copy_segregate_attributes(state, module);
+	if (ret) {
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index fc260eb6..356e8268 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -334,6 +334,13 @@ static const struct policydb_compat_info policydb_compat[] = {
 	 .ocon_num = OCON_IBENDPORT + 1,
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_SEGREGATEATTRIBUTE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_IBENDPORT + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
 	{
 	 .type = POLICY_MOD,
 	 .version = MOD_POLICYDB_VERSION_BASE,
@@ -460,6 +467,13 @@ static const struct policydb_compat_info policydb_compat[] = {
 	 .ocon_num = 0,
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_SEGREGATEATTRIBUTE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
 };
 
 #if 0
@@ -760,6 +774,21 @@ void avrule_list_destroy(avrule_t * x)
 	}
 }
 
+void segregate_attribute_init(segregate_attribute_t * x)
+{
+	memset(x, 0, sizeof(segregate_attribute_t));
+	ebitmap_init(&x->attrs);
+}
+
+
+void segregate_attribute_destroy(segregate_attribute_t * x)
+{
+	if (!x)
+		return;
+	ebitmap_destroy(&x->attrs);
+	free(x->source_filename);
+}
+
 /* 
  * Initialize the role table by implicitly adding role 'object_r'.  If
  * the policy is a module, set object_r's scope to be SCOPE_REQ,
@@ -1492,6 +1521,7 @@ void policydb_destroy(policydb_t * p)
 	unsigned int i;
 	role_allow_t *ra, *lra = NULL;
 	role_trans_t *tr, *ltr = NULL;
+	segregate_attribute_t *sattr, *sattr_next;
 
 	if (!p)
 		return;
@@ -1585,6 +1615,12 @@ void policydb_destroy(policydb_t * p)
 		free(p->attr_type_map);
 	}
 
+	for (sattr = p->segregate_attributes; sattr; sattr = sattr_next) {
+		sattr_next = sattr->next;
+		segregate_attribute_destroy(sattr);
+		free(sattr);
+	}
+
 	return;
 }
 
@@ -4174,6 +4210,39 @@ static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
 	return -1;
 }
 
+static int segregate_attributes_read(policydb_t * p, struct policy_file *fp)
+{
+	segregate_attribute_t *list = NULL;
+	uint32_t buf, nel, i;
+	int rc;
+
+	rc = next_entry(&buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf);
+	for (i = 0; i < nel; i++) {
+		segregate_attribute_t *sattr;
+
+		sattr = calloc(1, sizeof(segregate_attribute_t));
+		if (!sattr)
+			return -1;
+
+		if (ebitmap_read(&sattr->attrs, fp) < 0) {
+			ebitmap_destroy(&sattr->attrs);
+			free(sattr);
+			return -1;
+		}
+
+		if (list)
+			list->next = sattr;
+		else
+			p->segregate_attributes = sattr;
+		list = sattr;
+	}
+
+	return 0;
+}
+
 static sepol_security_class_t policydb_string_to_security_class(
 	struct policydb *policydb,
 	const char *class_name)
@@ -4570,6 +4639,12 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
 		}
 	}
 
+	if (p->policyvers >= MOD_POLICYDB_VERSION_SEGREGATEATTRIBUTE &&
+	    p->policy_type != POLICY_KERN) {
+		if (segregate_attributes_read(p, fp))
+			return POLICYDB_ERROR;
+	}
+
 	if (validate_policydb(fp->handle, p))
 		goto bad;
 
diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c
index 99d4eb7f..be969036 100644
--- a/libsepol/src/policydb_validate.c
+++ b/libsepol/src/policydb_validate.c
@@ -1270,6 +1270,32 @@ bad:
 	return -1;
 }
 
+static int validate_segregate_attributes(sepol_handle_t *handle, policydb_t *p, validate_t flavors[])
+{
+	segregate_attribute_t *sattr;
+	ebitmap_node_t *node;
+	unsigned int i;
+
+	for (sattr = p->segregate_attributes; sattr; sattr = sattr->next) {
+		if (ebitmap_cardinality(&sattr->attrs) < 2)
+			goto bad;
+
+		if (validate_ebitmap(&sattr->attrs, &flavors[SYM_TYPES]))
+			goto bad;
+
+		ebitmap_for_each_positive_bit(&sattr->attrs, node, i) {
+			if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB)
+				goto bad;
+		}
+	}
+
+	return 0;
+
+bad:
+	ERR(handle, "Invalid segregate attribute definition");
+	return -1;
+}
+
 static int validate_properties(sepol_handle_t *handle, policydb_t *p)
 {
 	switch (p->policy_type) {
@@ -1376,6 +1402,9 @@ int validate_policydb(sepol_handle_t *handle, policydb_t *p)
 	if (validate_permissives(handle, p, flavors))
 		goto bad;
 
+	if (validate_segregate_attributes(handle, p, flavors))
+		goto bad;
+
 	validate_array_destroy(flavors);
 
 	return 0;
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index 48ed21ea..d5c6df16 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -58,9 +58,9 @@ struct policy_data {
 static int avrule_write_list(policydb_t *p,
 			     avrule_t * avrules, struct policy_file *fp);
 
-static int ebitmap_write(ebitmap_t * e, struct policy_file *fp)
+static int ebitmap_write(const ebitmap_t * e, struct policy_file *fp)
 {
-	ebitmap_node_t *n;
+	const ebitmap_node_t *n;
 	uint32_t buf[32], bit, count;
 	uint64_t map;
 	size_t items;
@@ -2189,6 +2189,30 @@ static int role_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
 	return 0;
 }
 
+static int segregate_attributes_write(const policydb_t *p, struct policy_file *fp)
+{
+	const segregate_attribute_t *sattr;
+	size_t items;
+	uint32_t buf, count = 0;
+
+	for (sattr = p->segregate_attributes; sattr; sattr = sattr->next) {
+		if (__builtin_add_overflow(count, 1, &count))
+			return POLICYDB_ERROR;
+	}
+
+	buf = cpu_to_le32(count);
+	items = put_entry(&buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	for (sattr = p->segregate_attributes; sattr; sattr = sattr->next) {
+		if (ebitmap_write(&sattr->attrs, fp))
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
 /*
  * Write the configuration data in a policy database
  * structure to a policy database binary representation
@@ -2411,5 +2435,11 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
 		}
 	}
 
+	if (p->policyvers >= MOD_POLICYDB_VERSION_SEGREGATEATTRIBUTE &&
+	    p->policy_type != POLICY_KERN) {
+		if (segregate_attributes_write(p, fp))
+			return POLICYDB_ERROR;
+	}
+
 	return POLICYDB_SUCCESS;
 }
-- 
2.36.1


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

* [RFC PATCH 4/4] checkpolicy: add front-end support for segregate attributes
  2022-06-16 13:14 [RFC PATCH 1/4] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
  2022-06-16 13:14 ` [RFC PATCH 2/4] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
  2022-06-16 13:14 ` [RFC PATCH 3/4] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
@ 2022-06-16 13:14 ` Christian Göttsche
  2 siblings, 0 replies; 6+ messages in thread
From: Christian Göttsche @ 2022-06-16 13:14 UTC (permalink / raw)
  To: selinux

Support specifying segregate attributes.

The following two blocks are equivalent:

    segregate_attributes attr1, attr2, attr3;

    segregate_attributes attr1, attr2;
    segregate_attributes attr1, attr3;
    segregate_attributes attr2, attr3;

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 checkpolicy/policy_define.c | 74 +++++++++++++++++++++++++++++++++++++
 checkpolicy/policy_define.h |  1 +
 checkpolicy/policy_parse.y  |  5 +++
 checkpolicy/policy_scan.l   |  2 +
 4 files changed, 82 insertions(+)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 8bf36859..faa8c00f 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -1220,6 +1220,80 @@ exit:
 	return rc;
 }
 
+int define_segregate_attributes(void)
+{
+	char *id = NULL;
+	segregate_attribute_t *sattr = NULL;
+	int rc = -1;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	sattr = malloc(sizeof(segregate_attribute_t));
+	if (!sattr) {
+		yyerror("Out of memory!");
+		goto exit;
+	}
+
+	ebitmap_init(&sattr->attrs);
+	sattr->line = policydb_lineno;
+	sattr->source_line = source_lineno;
+	sattr->source_filename = strdup(source_file);
+	if (!sattr->source_filename) {
+		yyerror("Out of memory!");
+		goto exit;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		const type_datum_t *attr;
+
+		if (!is_id_in_scope(SYM_TYPES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			goto exit;
+		}
+
+		attr = hashtab_search(policydbp->p_types.table, id);
+		if (!attr) {
+			yyerror2("attribute %s is not declared", id);
+			goto exit;
+		}
+
+		if (attr->flavor != TYPE_ATTRIB) {
+			yyerror2("%s is a type, not an attribute", id);
+			goto exit;
+		}
+
+		if (ebitmap_get_bit(&sattr->attrs, attr->s.value - 1)) {
+			yyerror2("attribute %s used multiple times", id);
+			goto exit;
+		}
+
+		if (ebitmap_set_bit(&sattr->attrs, attr->s.value - 1, TRUE)) {
+			yyerror("Out of memory!");
+			goto exit;
+		}
+
+		free(id);
+	}
+
+	sattr->next = policydbp->segregate_attributes;
+	policydbp->segregate_attributes = sattr;
+
+	sattr = NULL;
+	rc = 0;
+exit:
+	if (sattr) {
+		free(sattr->source_filename);
+		ebitmap_destroy(&sattr->attrs);
+		free(sattr);
+	}
+	free(id);
+	return rc;
+}
+
 static int add_aliases_to_type(type_datum_t * type)
 {
 	char *id;
diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
index 50a7ba78..f55d0b17 100644
--- a/checkpolicy/policy_define.h
+++ b/checkpolicy/policy_define.h
@@ -68,6 +68,7 @@ int define_type(int alias);
 int define_user(void);
 int define_validatetrans(constraint_expr_t *expr);
 int expand_attrib(void);
+int define_segregate_attributes(void);
 int insert_id(const char *id,int push);
 int insert_separator(int push);
 role_datum_t *define_role_dom(role_datum_t *r);
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
index 45f973ff..acd6096d 100644
--- a/checkpolicy/policy_parse.y
+++ b/checkpolicy/policy_parse.y
@@ -104,6 +104,7 @@ typedef int (* require_func_t)(int pass);
 %token ALIAS
 %token ATTRIBUTE
 %token EXPANDATTRIBUTE
+%token SEGREGATEATTRIBUTES
 %token BOOL
 %token TUNABLE
 %token IF
@@ -320,6 +321,7 @@ rbac_decl		: attribute_role_def
 			;
 te_decl			: attribute_def
                         | expandattribute_def
+                        | segregateattributes_def
                         | type_def
                         | typealias_def
                         | typeattribute_def
@@ -337,6 +339,9 @@ attribute_def           : ATTRIBUTE identifier ';'
 expandattribute_def     : EXPANDATTRIBUTE names bool_val ';'
                         { if (expand_attrib()) return -1;}
                         ;
+segregateattributes_def : SEGREGATEATTRIBUTES identifier ',' id_comma_list ';'
+                        { if (define_segregate_attributes()) return -1;}
+                        ;
 type_def		: TYPE identifier alias_def opt_attr_list ';'
                         {if (define_type(1)) return -1;}
 	                | TYPE identifier opt_attr_list ';'
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index 9fefea7b..d865dcb6 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -123,6 +123,8 @@ ATTRIBUTE |
 attribute			{ return(ATTRIBUTE); }
 EXPANDATTRIBUTE |
 expandattribute                 { return(EXPANDATTRIBUTE); }
+SEGREGATE_ATTRIBUTES |
+segregate_attributes		{ return(SEGREGATEATTRIBUTES); }
 TYPE_TRANSITION |
 type_transition			{ return(TYPE_TRANSITION); }
 TYPE_MEMBER |
-- 
2.36.1


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

* Re: [RFC PATCH 3/4] libsepol: add compile-time constraint for mutual exclusive attributes
  2022-06-16 13:14 ` [RFC PATCH 3/4] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
@ 2022-06-28 21:54   ` Nicolas Iooss
  0 siblings, 0 replies; 6+ messages in thread
From: Nicolas Iooss @ 2022-06-28 21:54 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Thu, Jun 16, 2022 at 3:14 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Add a new compile-time constraint, similar to neverallow, which enables
> to specify two or more type attributes to be mutual exclusive.  This
> means no type can be associated with more than one of them.
>
> The constraints are stored as a linked-list in the policy for modular
> policies, by a new modular policy version, and are discarded in kernel
> policies, not needing any kernel support.
>
> Some Reference Policy examples:
>
>     unpriv_userdomain, admindomain:
>
>         <no violations>
>
>     client_packet_type, server_packet_type:
>
>         <no violations>
>
>     auth_file_type, non_auth_file_type:
>
>         <no violations>
>
>     pseudofs, xattrfs, noxattrfs:
>
>          <no violations>
>
>     reserved_port_type, unreserved_port_type:
>
>          <no violations>
>
>     security_file_type, non_security_file_type:
>
>         libsepol.check_segregate_attributes: segregate_attributes violated by type dnssec_t associated with attributes security_file_type and non_security_file_type
>
>     ibendport_type, packet_type, sysctl_type, device_node, ibpkey_type,
>     sysfs_types, domain, boolean_type, netif_type, file_type, node_type,
>     proc_type, port_type:
>
>         libsepol.check_segregate_attributes: segregate_attributes violated by type virt_content_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type sysctl_fs_t associated with attributes sysctl_type and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type initrc_devpts_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type qemu_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type user_devpts_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type dockerc_t associated with attributes domain and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type cpu_online_t associated with attributes sysfs_types and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type cardmgr_dev_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type sysctl_t associated with attributes sysctl_type and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type bootloader_tmp_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type xen_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type svirt_prot_exec_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type xen_devpts_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type proc_t associated with attributes file_type and proc_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type sysfs_t associated with attributes sysfs_types and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type proc_xen_t associated with attributes file_type and proc_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type svirt_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type virt_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: segregate_attributes violated by type container_file_t associated with attributes device_node and file_type
>
>     libsepol.check_assertions: 20 segregate attribute failures occurred
>
> Closes: https://github.com/SELinuxProject/selinux/issues/42
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>


Hello,

Thanks for your patches. This feature seems to be interesting to help
ensuring using a sane policy at compile-time. The example you gave
based on refpolicy clearly show a nice use-case of this feature.

The code looks good and quite simple. It nevertheless lacks some tests
to ensure this feature is implemented in a way which is the intended
one. I know that libsepol/tests/ is probably not the most
developer-friendly test framework, but it can help catch issues caused
by future code refactoring. In order to apply these patches, I would
expect at least a test with a policy which uses some attributes in a
correct way and a test with a policy which triggers a violation.

Moreover, your changes are only about the .te policy compiler and
(unless I missed something) ignore the CIL support. It makes sense for
a feature which mainly targets the Reference Policy, but the issue it
solves can probably also be found in policies written in CIL or in
languages which compile to CIL. Would it make sense to link
segregate_attributes with the CIL compiler too? (I do not have a clear
opinion on this question)

Cheers,
Nicolas


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

* Re: [RFC PATCH 2/4] libsepol: add ebitmap iterator wrapper with startnode
  2022-06-16 13:14 ` [RFC PATCH 2/4] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
@ 2022-06-28 22:01   ` Nicolas Iooss
  0 siblings, 0 replies; 6+ messages in thread
From: Nicolas Iooss @ 2022-06-28 22:01 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Thu, Jun 16, 2022 at 3:14 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Similar like ebitmap_for_each_bit() iterates over all bits of an ebitmap
> add ebitmap_for_each_bit_starting() iterating over all bits starting
> from a specific node and bit, which can be from an outer iteration.
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
>  libsepol/include/sepol/policydb/ebitmap.h | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/libsepol/include/sepol/policydb/ebitmap.h b/libsepol/include/sepol/policydb/ebitmap.h
> index 81d0c7a6..83ff54c2 100644
> --- a/libsepol/include/sepol/policydb/ebitmap.h
> +++ b/libsepol/include/sepol/policydb/ebitmap.h
> @@ -80,6 +80,13 @@ static inline int ebitmap_node_get_bit(const ebitmap_node_t * n, unsigned int bi
>  #define ebitmap_for_each_positive_bit(e, n, bit) \
>         ebitmap_for_each_bit(e, n, bit) if (ebitmap_node_get_bit(n, bit)) \
>
> +#define ebitmap_for_each_bit_starting(e, startnode, startbit, n, bit) \
> +       n = startnode; \
> +       for (bit = ebitmap_next(&n, startbit); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
> +
> +#define ebitmap_for_each_positive_bit_starting(e, startnode, startbit, n, bit) \
> +       ebitmap_for_each_bit_starting(e, startnode, startbit, n, bit) if (ebitmap_node_get_bit(n, bit)) \
> +
>  extern int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2);
>  extern int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2);
>  extern int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1);
> --
> 2.36.1
>

I find the names "..._starting" confusing: the first bit which is
iterated is the next one after "startnode/startbit". Moreover,
startnode really needs to be not NULL for this to work, and in
practice it works because this macro is used inside a
ebitmap_for_each_bit() loop which ensures that startnode != NULL. To
avoid possible semantic issues, I suggest naming these macros
"..._after" instead: they are about iterating the bits of an ebitmap
after some known bit. (Of course this is my humble opinion and please
feel free to disagree and to keep the name you chose if you do)

Thanks,
Nicolas


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

end of thread, other threads:[~2022-06-28 22:01 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-16 13:14 [RFC PATCH 1/4] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
2022-06-16 13:14 ` [RFC PATCH 2/4] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
2022-06-28 22:01   ` Nicolas Iooss
2022-06-16 13:14 ` [RFC PATCH 3/4] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
2022-06-28 21:54   ` Nicolas Iooss
2022-06-16 13:14 ` [RFC PATCH 4/4] checkpolicy: add front-end support for segregate attributes Christian Göttsche

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.