selinux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c
@ 2022-07-21 15:05 Christian Göttsche
  2022-07-21 15:05 ` [PATCH v3 2/8] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
                   ` (7 more replies)
  0 siblings, 8 replies; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 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] 17+ messages in thread

* [PATCH v3 2/8] libsepol: add ebitmap iterator wrapper with startnode
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
@ 2022-07-21 15:05 ` Christian Göttsche
  2022-08-08 15:04   ` James Carter
  2022-07-21 15:05 ` [PATCH v3 3/8] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 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>
---
v2:
   * use _after suffix
   * reorder parameters
---
 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..4696805f 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_after(e, n, bit, startnode, startbit) \
+	n = startnode; \
+	for (bit = ebitmap_next(&n, startbit); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
+#define ebitmap_for_each_positive_bit_after(e, n, bit, startnode, startbit) \
+	ebitmap_for_each_bit_after(e, n, bit, startnode, startbit) 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] 17+ messages in thread

* [PATCH v3 3/8] libsepol: add compile-time constraint for mutual exclusive attributes
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
  2022-07-21 15:05 ` [PATCH v3 2/8] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
@ 2022-07-21 15:05 ` Christian Göttsche
  2022-08-08 17:02   ` James Carter
  2022-07-21 15:05 ` [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes Christian Göttsche
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 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 violation, 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 violation, type sysctl_fs_t associated with attributes sysctl_type and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type sysctl_t associated with attributes sysctl_type and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type virt_content_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type initrc_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type qemu_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type user_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type cardmgr_dev_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type bootloader_tmp_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type xen_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type svirt_prot_exec_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type xen_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type svirt_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type virt_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type container_file_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type cpu_online_t associated with attributes sysfs_types and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type sysfs_t associated with attributes sysfs_types and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type dockerc_t associated with attributes domain and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type proc_t associated with attributes file_type and proc_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type proc_xen_t associated with attributes file_type and proc_type

    libsepol.check_assertions: 20 Segregate Attributes failures occurred

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

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
v3:
   - drop source location information:
     this information was already lost for binary modular policies and
     CIL policies; also typeattribute statements have none and the few
     segregate_attributes statements can be easily grepped
   - misc renaming
v2:
   rebase onto _after suffix change
---
 libsepol/include/sepol/policydb/policydb.h | 15 ++++-
 libsepol/src/assertion.c                   | 57 +++++++++++++---
 libsepol/src/expand.c                      | 45 ++++++++++++-
 libsepol/src/kernel_to_conf.c              | 38 ++++++++++-
 libsepol/src/link.c                        | 44 +++++++++++++
 libsepol/src/policydb.c                    | 76 ++++++++++++++++++++++
 libsepol/src/policydb_validate.c           | 29 +++++++++
 libsepol/src/write.c                       | 34 +++++++++-
 8 files changed, 325 insertions(+), 13 deletions(-)

diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index de0068a6..d62d030c 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -192,6 +192,12 @@ typedef struct type_datum {
 	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/* Mutual exclusive attributes */
+typedef struct segregate_attributes_rule {
+	ebitmap_t attrs;	/* mutual exclusive attributes */
+	struct segregate_attributes_rule *next;
+} segregate_attributes_rule_t;
+
 /*
  * Properties of type_datum
  * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
@@ -605,6 +611,10 @@ 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).
+	   stored as linked list */
+	segregate_attributes_rule_t *segregate_attributes;
+
 	unsigned policyvers;
 
 	unsigned handle_unknown;
@@ -696,6 +706,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_attributes_rule_init(segregate_attributes_rule_t * x);
+extern void segregate_attributes_rule_destroy(segregate_attributes_rule_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 +795,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_SEGREGATE_ATTRIBUTES	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_SEGREGATE_ATTRIBUTES
 
 #define POLICYDB_CONFIG_MLS    1
 
diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c
index 161874c3..a6dda570 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,44 @@ int check_assertion(policydb_t *p, avrule_t *avrule)
 	return rc;
 }
 
+static int check_segregate_attributes(sepol_handle_t *handle, const policydb_t *p)
+{
+	const segregate_attributes_rule_t *sattr;
+	int errors = 0, rc;
+
+	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_after(&sattr->attrs, second_node, second_bit, first_node, first_bit) {
+				ebitmap_t attr_union;
+				ebitmap_node_t *type_node;
+				unsigned int type_bit;
+
+				rc = ebitmap_and(&attr_union, &p->attr_type_map[first_bit], &p->attr_type_map[second_bit]);
+				if (rc < 0)
+					return rc;
+
+				ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) {
+					ERR(handle, "Segregate Attributes violation, 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)
 {
@@ -542,13 +580,6 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
 	avrule_t *a;
 	unsigned long errors = 0;
 
-	if (!avrules) {
-		/* Since assertions are stored in avrules, if it is NULL
-		   there won't be any to check. This also prevents an invalid
-		   free if the avtabs are never initialized */
-		return 0;
-	}
-
 	for (a = avrules; a != NULL; a = a->next) {
 		if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
 			continue;
@@ -570,5 +601,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 Attributes failures occurred", rc);
+		errors += rc;
+	}
+
 	return errors ? -1 : 0;
 }
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index 8d19850e..6f52d1ff 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,45 @@ static int genfs_copy(expand_state_t * state)
 	return 0;
 }
 
+static int segregate_attributes_copy(expand_state_t *state)
+{
+	const segregate_attributes_rule_t *old;
+	segregate_attributes_rule_t *list = NULL;
+
+	for (old = state->base->segregate_attributes; old; old = old->next) {
+		segregate_attributes_rule_t *new;
+
+		new = malloc(sizeof(segregate_attributes_rule_t));
+		if (!new) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		segregate_attributes_rule_init(new);
+
+		if (map_ebitmap(&old->attrs, &new->attrs, state->typemap)) {
+			ERR(state->handle, "out of memory");
+			ebitmap_destroy(&new->attrs);
+			free(new);
+			return -1;
+		}
+
+		if (list)
+			list->next = new;
+		else {
+			if (state->out->segregate_attributes) {
+				segregate_attributes_rule_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 +3212,10 @@ int expand_module(sepol_handle_t * handle,
 	if (genfs_copy(&state))
 		goto cleanup;
 
+	/* copy segregate attributes */
+	if (segregate_attributes_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/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index 63dffd9b..f119d572 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -1839,6 +1839,33 @@ exit:
 	return rc;
 }
 
+static int write_segregate_attributes_to_conf(FILE *out, const struct policydb *pdb)
+{
+	const segregate_attributes_rule_t *sattr;
+
+	for (sattr = pdb->segregate_attributes; sattr; sattr = sattr->next) {
+		struct ebitmap_node *node;
+		unsigned int bit;
+		int first = 1;
+
+		sepol_printf(out, "segregate_attributes ");
+
+		ebitmap_for_each_positive_bit(&sattr->attrs, node, bit) {
+			if (first) {
+				first = 0;
+			} else {
+				sepol_printf(out, ", ");
+			}
+
+			sepol_printf(out, "%s", pdb->p_type_val_to_name[bit - 1]);
+		}
+
+		sepol_printf(out, ";\n");
+	}
+
+	return 0;
+}
+
 struct map_filename_trans_args {
 	struct policydb *pdb;
 	struct strs *strs;
@@ -3200,7 +3227,16 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
 	if (rc != 0) {
 		goto exit;
 	}
-	write_filename_trans_rules_to_conf(out, pdb);
+
+	rc = write_segregate_attributes_to_conf(out, pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = write_filename_trans_rules_to_conf(out, pdb);
+	if (rc != 0) {
+		goto exit;
+	}
 
 	if (pdb->mls) {
 		rc = write_range_trans_rules_to_conf(out, pdb);
diff --git a/libsepol/src/link.c b/libsepol/src/link.c
index cbe4cea4..1650a9c0 100644
--- a/libsepol/src/link.c
+++ b/libsepol/src/link.c
@@ -1857,6 +1857,45 @@ 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_attributes_rule_t *src_sattr;
+	segregate_attributes_rule_t *list = NULL;
+
+	for (src_sattr = module->policy->segregate_attributes; src_sattr; src_sattr = src_sattr->next) {
+		segregate_attributes_rule_t *new_sattr;
+
+		new_sattr = malloc(sizeof(segregate_attributes_rule_t));
+		if (!new_sattr) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		segregate_attributes_rule_init(new_sattr);
+
+		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;
+		}
+
+		if (list)
+			list->next = new_sattr;
+		else {
+			if (state->base->segregate_attributes) {
+				segregate_attributes_rule_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 +1930,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..9dbb9f44 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_SEGREGATE_ATTRIBUTES,
+	 .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_SEGREGATE_ATTRIBUTES,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
 };
 
 #if 0
@@ -760,6 +774,20 @@ void avrule_list_destroy(avrule_t * x)
 	}
 }
 
+void segregate_attributes_rule_init(segregate_attributes_rule_t * x)
+{
+	ebitmap_init(&x->attrs);
+	x->next = NULL;
+}
+
+
+void segregate_attributes_rule_destroy(segregate_attributes_rule_t * x)
+{
+	if (!x)
+		return;
+	ebitmap_destroy(&x->attrs);
+}
+
 /* 
  * 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 +1520,7 @@ void policydb_destroy(policydb_t * p)
 	unsigned int i;
 	role_allow_t *ra, *lra = NULL;
 	role_trans_t *tr, *ltr = NULL;
+	segregate_attributes_rule_t *sattr, *sattr_next;
 
 	if (!p)
 		return;
@@ -1585,6 +1614,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_attributes_rule_destroy(sattr);
+		free(sattr);
+	}
+
 	return;
 }
 
@@ -4174,6 +4209,41 @@ 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_attributes_rule_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_attributes_rule_t *sattr;
+
+		sattr = malloc(sizeof(segregate_attributes_rule_t));
+		if (!sattr)
+			return -1;
+
+		segregate_attributes_rule_init(sattr);
+
+		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 +4640,12 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
 		}
 	}
 
+	if (p->policyvers >= MOD_POLICYDB_VERSION_SEGREGATE_ATTRIBUTES &&
+	    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..6331c3ce 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_attributes_rule_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 attributes 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 a9fdf93a..81323df9 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;
@@ -2191,6 +2191,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_attributes_rule_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
@@ -2413,5 +2437,11 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
 		}
 	}
 
+	if (p->policyvers >= MOD_POLICYDB_VERSION_SEGREGATE_ATTRIBUTES &&
+	    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] 17+ messages in thread

* [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
  2022-07-21 15:05 ` [PATCH v3 2/8] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
  2022-07-21 15:05 ` [PATCH v3 3/8] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
@ 2022-07-21 15:05 ` Christian Göttsche
  2022-08-08 17:09   ` James Carter
  2022-07-21 15:05 ` [PATCH v3 5/8] libsepol/tests: add test " Christian Göttsche
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 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 | 66 +++++++++++++++++++++++++++++++++++++
 checkpolicy/policy_define.h |  1 +
 checkpolicy/policy_parse.y  |  5 +++
 checkpolicy/policy_scan.l   |  2 ++
 4 files changed, 74 insertions(+)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 8bf36859..cf6fbf08 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -1220,6 +1220,72 @@ exit:
 	return rc;
 }
 
+int define_segregate_attributes(void)
+{
+	char *id = NULL;
+	segregate_attributes_rule_t *sattr = NULL;
+	int rc = -1;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	sattr = malloc(sizeof(segregate_attributes_rule_t));
+	if (!sattr) {
+		yyerror("Out of memory!");
+		goto exit;
+	}
+
+	ebitmap_init(&sattr->attrs);
+
+	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) {
+		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] 17+ messages in thread

* [PATCH v3 5/8] libsepol/tests: add test for segregate attributes
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
                   ` (2 preceding siblings ...)
  2022-07-21 15:05 ` [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes Christian Göttsche
@ 2022-07-21 15:05 ` Christian Göttsche
  2022-07-21 15:05 ` [PATCH v3 6/8] libsepol/cil: add support " Christian Göttsche
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 UTC (permalink / raw)
  To: selinux

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libsepol/tests/libsepol-tests.c               |   2 +
 .../tests/policies/test-sattrs/single.conf    |  87 ++++++++
 .../policies/test-sattrs/split_base.conf      |  53 +++++
 .../policies/test-sattrs/split_module1.conf   |   9 +
 .../policies/test-sattrs/split_module2.conf   |   9 +
 .../policies/test-sattrs/split_module3.conf   |   9 +
 libsepol/tests/test-segregateattributes.c     | 197 ++++++++++++++++++
 libsepol/tests/test-segregateattributes.h     |  10 +
 8 files changed, 376 insertions(+)
 create mode 100644 libsepol/tests/policies/test-sattrs/single.conf
 create mode 100644 libsepol/tests/policies/test-sattrs/split_base.conf
 create mode 100644 libsepol/tests/policies/test-sattrs/split_module1.conf
 create mode 100644 libsepol/tests/policies/test-sattrs/split_module2.conf
 create mode 100644 libsepol/tests/policies/test-sattrs/split_module3.conf
 create mode 100644 libsepol/tests/test-segregateattributes.c
 create mode 100644 libsepol/tests/test-segregateattributes.h

diff --git a/libsepol/tests/libsepol-tests.c b/libsepol/tests/libsepol-tests.c
index dc8fd5ce..989c7cd3 100644
--- a/libsepol/tests/libsepol-tests.c
+++ b/libsepol/tests/libsepol-tests.c
@@ -23,6 +23,7 @@
 #include "test-expander.h"
 #include "test-deps.h"
 #include "test-downgrade.h"
+#include "test-segregateattributes.h"
 
 #include <CUnit/Basic.h>
 #include <CUnit/Console.h>
@@ -69,6 +70,7 @@ static bool do_tests(int interactive, int verbose)
 	DECLARE_SUITE(expander);
 	DECLARE_SUITE(deps);
 	DECLARE_SUITE(downgrade);
+	DECLARE_SUITE(sattrs);
 
 	if (verbose)
 		CU_basic_set_mode(CU_BRM_VERBOSE);
diff --git a/libsepol/tests/policies/test-sattrs/single.conf b/libsepol/tests/policies/test-sattrs/single.conf
new file mode 100644
index 00000000..1666f842
--- /dev/null
+++ b/libsepol/tests/policies/test-sattrs/single.conf
@@ -0,0 +1,87 @@
+class process
+class blk_file
+class chr_file
+class dir
+class fifo_file
+class file
+class lnk_file
+class sock_file
+
+sid kernel
+sid security
+sid unlabeled
+sid file
+sid port
+sid netif
+sid netmsg
+sid node
+sid devnull
+
+class process { dyntransition transition }
+class file { write }
+
+ifdef(`enable_mls',`
+sensitivity s0;
+dominance { s0 }
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write } ( h1 dom h2 );
+')
+
+#
+# Test start
+#
+
+attribute test1_attr1;
+attribute test1_attr2;
+type test1_type;
+typeattribute test1_type test1_attr1;
+typeattribute test1_type test1_attr2;
+segregate_attributes test1_attr1, test1_attr2;
+
+
+attribute test2_attr1;
+attribute test2_attr2;
+attribute test2_attr3;
+type test2_type1;
+type test2_type2;
+type test2_type3;
+type test2_type4;
+typeattribute test2_type1 test2_attr1;
+typeattribute test2_type1 test2_attr2;
+typeattribute test2_type2 test2_attr1;
+typeattribute test2_type2 test2_attr3;
+typeattribute test2_type3 test2_attr2;
+typeattribute test2_type3 test2_attr3;
+typeattribute test2_type4 test2_attr1;
+typeattribute test2_type4 test2_attr2;
+typeattribute test2_type4 test2_attr3;
+segregate_attributes test2_attr1, test2_attr2, test2_attr3;
+
+#
+# Test End
+#
+
+type sys_isid;
+allow sys_isid self : process { dyntransition transition };
+role sys_role;
+role sys_role types sys_isid;
+gen_user(sys_user,, sys_role, s0, s0 - s0:c0.c23)
+sid kernel gen_context(sys_user:sys_role:sys_isid, s0)
+sid security gen_context(sys_user:sys_role:sys_isid, s0)
+sid unlabeled gen_context(sys_user:sys_role:sys_isid, s0)
+sid file gen_context(sys_user:sys_role:sys_isid, s0)
+sid port gen_context(sys_user:sys_role:sys_isid, s0)
+sid netif gen_context(sys_user:sys_role:sys_isid, s0)
+sid netmsg gen_context(sys_user:sys_role:sys_isid, s0)
+sid node gen_context(sys_user:sys_role:sys_isid, s0)
+sid devnull gen_context(sys_user:sys_role:sys_isid, s0)
+fs_use_trans devpts gen_context(sys_user:sys_role:sys_isid, s0);
+fs_use_trans devtmpfs gen_context(sys_user:sys_role:sys_isid, s0);
diff --git a/libsepol/tests/policies/test-sattrs/split_base.conf b/libsepol/tests/policies/test-sattrs/split_base.conf
new file mode 100644
index 00000000..6fba8cdd
--- /dev/null
+++ b/libsepol/tests/policies/test-sattrs/split_base.conf
@@ -0,0 +1,53 @@
+class process
+class blk_file
+class chr_file
+class dir
+class fifo_file
+class file
+class lnk_file
+class sock_file
+
+sid kernel
+sid security
+sid unlabeled
+sid file
+sid port
+sid netif
+sid netmsg
+sid node
+sid devnull
+
+class process { dyntransition transition }
+class file { write }
+
+ifdef(`enable_mls',`
+sensitivity s0;
+dominance { s0 }
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write } ( h1 dom h2 );
+')
+
+type sys_isid;
+allow sys_isid self : process { dyntransition transition };
+role sys_role;
+role sys_role types sys_isid;
+gen_user(sys_user,, sys_role, s0, s0 - s0:c0.c23)
+sid kernel gen_context(sys_user:sys_role:sys_isid, s0)
+sid security gen_context(sys_user:sys_role:sys_isid, s0)
+sid unlabeled gen_context(sys_user:sys_role:sys_isid, s0)
+sid file gen_context(sys_user:sys_role:sys_isid, s0)
+sid port gen_context(sys_user:sys_role:sys_isid, s0)
+sid netif gen_context(sys_user:sys_role:sys_isid, s0)
+sid netmsg gen_context(sys_user:sys_role:sys_isid, s0)
+sid node gen_context(sys_user:sys_role:sys_isid, s0)
+sid devnull gen_context(sys_user:sys_role:sys_isid, s0)
+fs_use_trans devpts gen_context(sys_user:sys_role:sys_isid, s0);
+fs_use_trans devtmpfs gen_context(sys_user:sys_role:sys_isid, s0);
diff --git a/libsepol/tests/policies/test-sattrs/split_module1.conf b/libsepol/tests/policies/test-sattrs/split_module1.conf
new file mode 100644
index 00000000..52b5f248
--- /dev/null
+++ b/libsepol/tests/policies/test-sattrs/split_module1.conf
@@ -0,0 +1,9 @@
+module sattrs_test_1 1.0;
+
+require {
+	type test_type_t;
+}
+
+attribute attr1;
+
+typeattribute test_type_t attr1;
diff --git a/libsepol/tests/policies/test-sattrs/split_module2.conf b/libsepol/tests/policies/test-sattrs/split_module2.conf
new file mode 100644
index 00000000..6b6128f7
--- /dev/null
+++ b/libsepol/tests/policies/test-sattrs/split_module2.conf
@@ -0,0 +1,9 @@
+module sattrs_test_2 1.0;
+
+require {
+	type test_type_t;
+}
+
+attribute attr2;
+
+typeattribute test_type_t attr2;
diff --git a/libsepol/tests/policies/test-sattrs/split_module3.conf b/libsepol/tests/policies/test-sattrs/split_module3.conf
new file mode 100644
index 00000000..050b9228
--- /dev/null
+++ b/libsepol/tests/policies/test-sattrs/split_module3.conf
@@ -0,0 +1,9 @@
+module sattrs_test_3 1.0;
+
+require {
+	attribute attr1, attr2;
+}
+
+type test_type_t;
+
+segregate_attributes attr1, attr2;
diff --git a/libsepol/tests/test-segregateattributes.c b/libsepol/tests/test-segregateattributes.c
new file mode 100644
index 00000000..4a21fb06
--- /dev/null
+++ b/libsepol/tests/test-segregateattributes.c
@@ -0,0 +1,197 @@
+#define _GNU_SOURCE
+
+#include "test-segregateattributes.h"
+
+#include "helpers.h"
+#include "test-common.h"
+
+#include <sepol/debug.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+
+extern int mls;
+
+int sattrs_test_init(void)
+{
+	return 0;
+}
+
+int sattrs_test_cleanup(void)
+{
+	return 0;
+}
+
+static struct msg_list {
+	char *msg;
+	struct msg_list *next;
+} *messages;
+
+static void messages_clean(void)
+{
+	while (messages) {
+		struct msg_list *n = messages->next;
+		free(messages->msg);
+		free(messages);
+		messages = n;
+	}
+}
+
+static void messages_check(unsigned count, const char *const expected[count])
+{
+	unsigned i;
+	const struct msg_list *m = messages;
+
+	for (i = 0; i < count; i++, m = m->next) {
+		if (!m) {
+			CU_FAIL("less messages than expected");
+			return;
+		}
+
+		if (strcmp(expected[i], m->msg) != 0) {
+			CU_FAIL("messages differs from expected");
+			fprintf(stderr, "\n<expected: '%s', got: '%s'>\n", expected[i], m->msg);
+		}
+	}
+
+	if (m) {
+		CU_FAIL("more messages than expected");
+		fprintf(stderr, "\n<next message: '%s'>\n", m->msg);
+	}
+}
+
+#ifdef __GNUC__
+__attribute__ ((format(printf, 3, 4)))
+#endif
+static void msg_handler(void *varg __attribute__ ((unused)),
+			sepol_handle_t * handle,
+			const char *fmt, ...)
+{
+	char *msg;
+	va_list ap;
+
+	va_start(ap, fmt);
+	vasprintf(&msg, fmt, ap);
+	va_end(ap);
+
+	struct msg_list *new = malloc(sizeof(struct msg_list));
+	new->msg = msg;
+	new->next = messages;
+	messages = new;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
+
+static void test_sattrs_single(void)
+{
+	policydb_t basemod, base_expanded;
+	sepol_handle_t *handle;
+	const char *const expected_messages[] = {
+		"7 Segregate Attributes failures occurred",
+		"Segregate Attributes violation, type test1_type associated with attributes test1_attr1 and test1_attr2",
+		"Segregate Attributes violation, type test2_type3 associated with attributes test2_attr2 and test2_attr3",
+		"Segregate Attributes violation, type test2_type4 associated with attributes test2_attr2 and test2_attr3",
+		"Segregate Attributes violation, type test2_type2 associated with attributes test2_attr1 and test2_attr3",
+		"Segregate Attributes violation, type test2_type4 associated with attributes test2_attr1 and test2_attr3",
+		"Segregate Attributes violation, type test2_type1 associated with attributes test2_attr1 and test2_attr2",
+		"Segregate Attributes violation, type test2_type4 associated with attributes test2_attr1 and test2_attr2",
+	};
+
+	if (policydb_init(&base_expanded))
+		CU_FAIL_FATAL("Failed to initialize policy");
+
+	if (test_load_policy(&basemod, POLICY_BASE, mls, "test-sattrs", "single.conf"))
+		CU_FAIL_FATAL("Failed to load policy");
+
+	if (link_modules(NULL, &basemod, NULL, 0, 0))
+		CU_FAIL_FATAL("Failed to link base module");
+
+	if (expand_module(NULL, &basemod, &base_expanded, 0, 0))
+		CU_FAIL_FATAL("Failed to expand policy");
+
+	if ((handle = sepol_handle_create()) == NULL)
+		CU_FAIL_FATAL("Failed to initialize handle");
+
+	sepol_msg_set_callback(handle, msg_handler, NULL);
+
+	if (check_assertions(handle, &base_expanded, NULL) != -1)
+		CU_FAIL("Assertions did not trigger");
+
+	messages_check(ARRAY_SIZE(expected_messages), expected_messages);
+
+	sepol_handle_destroy(handle);
+	messages_clean();
+	policydb_destroy(&basemod);
+	policydb_destroy(&base_expanded);
+}
+
+#define NUM_MODS 3
+
+static void test_sattrs_split(void)
+{
+	policydb_t basemod, base_expanded;
+	policydb_t *modules[NUM_MODS];
+	const char *policies[NUM_MODS] = { "split_module1.conf", "split_module2.conf", "split_module3.conf" };
+	sepol_handle_t *handle;
+	const char *const expected_messages[] = {
+		"1 Segregate Attributes failures occurred",
+		"Segregate Attributes violation, type test_type_t associated with attributes attr1 and attr2",
+	};
+	unsigned i;
+
+	if (policydb_init(&base_expanded))
+		CU_FAIL_FATAL("Failed to initialize policy");
+
+	if (test_load_policy(&basemod, POLICY_BASE, mls, "test-sattrs", "split_base.conf"))
+		CU_FAIL_FATAL("Failed to load policy");
+
+	for (i = 0; i < NUM_MODS; i++) {
+		modules[i] = calloc(1, sizeof(*modules[i]));
+		if (!modules[i])
+			CU_FAIL_FATAL("Failed to allocate module");
+
+		if (test_load_policy(modules[i], POLICY_MOD, mls, "test-sattrs", policies[i]))
+			CU_FAIL_FATAL("Failed to load module");
+	}
+
+	if (link_modules(NULL, &basemod, modules, 3, 0))
+		CU_FAIL_FATAL("Failed to link base module");
+
+	if (expand_module(NULL, &basemod, &base_expanded, 0, 0))
+		CU_FAIL_FATAL("Failed to expand policy");
+
+	if ((handle = sepol_handle_create()) == NULL)
+		CU_FAIL_FATAL("Failed to initialize handle");
+
+	sepol_msg_set_callback(handle, msg_handler, NULL);
+
+	if (check_assertions(handle, &base_expanded, NULL) != -1)
+		CU_FAIL("Assertions did not trigger");
+
+	messages_check(ARRAY_SIZE(expected_messages), expected_messages);
+
+	sepol_handle_destroy(handle);
+	messages_clean();
+	for (i = 0; i < NUM_MODS; i++) {
+		policydb_destroy(modules[i]);
+		free(modules[i]);
+	}
+	policydb_destroy(&basemod);
+	policydb_destroy(&base_expanded);
+}
+
+int sattrs_add_tests(CU_pSuite suite)
+{
+	if (NULL == CU_add_test(suite, "sattrs_single", test_sattrs_single)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	if (NULL == CU_add_test(suite, "sattrs_split", test_sattrs_split)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+
+	return 0;
+}
diff --git a/libsepol/tests/test-segregateattributes.h b/libsepol/tests/test-segregateattributes.h
new file mode 100644
index 00000000..a63c59f4
--- /dev/null
+++ b/libsepol/tests/test-segregateattributes.h
@@ -0,0 +1,10 @@
+#ifndef TEST_SEGREGATEATTRIBUTES_H__
+#define TEST_SEGREGATEATTRIBUTES_H__
+
+#include <CUnit/Basic.h>
+
+int sattrs_test_init(void);
+int sattrs_test_cleanup(void);
+int sattrs_add_tests(CU_pSuite suite);
+
+#endif  /* TEST_SEGREGATEATTRIBUTES_H__ */
-- 
2.36.1


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

* [PATCH v3 6/8] libsepol/cil: add support for segregate attributes
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
                   ` (3 preceding siblings ...)
  2022-07-21 15:05 ` [PATCH v3 5/8] libsepol/tests: add test " Christian Göttsche
@ 2022-07-21 15:05 ` Christian Göttsche
  2022-08-08 17:15   ` James Carter
  2022-07-21 15:05 ` [PATCH v3 7/8] secilc: run tests against development version of libsepol Christian Göttsche
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 UTC (permalink / raw)
  To: selinux

Support the compile time constraint with the following syntax:

    (segregateattributes (attr1 attr2 [...]))

and reports like:

    ...
    Qualifying Names
    Compile post process
    Building policy binary
    Checking Neverallows
    Checking Segregate Attributes
    Segregate Attributes violation, type test_type associated with attributes attr1 attr2
    Checking User Bounds
    Checking Role Bounds
    Checking Type Bounds
    Failed to generate binary
    Failed to build policydb

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libsepol/cil/src/cil.c             | 17 +++++++
 libsepol/cil/src/cil_binary.c      | 75 ++++++++++++++++++++++++++++++
 libsepol/cil/src/cil_build_ast.c   | 58 +++++++++++++++++++++++
 libsepol/cil/src/cil_build_ast.h   |  2 +
 libsepol/cil/src/cil_copy_ast.c    | 18 +++++++
 libsepol/cil/src/cil_flavor.h      |  1 +
 libsepol/cil/src/cil_internal.h    |  8 ++++
 libsepol/cil/src/cil_policy.c      | 26 +++++++++++
 libsepol/cil/src/cil_reset_ast.c   |  8 ++++
 libsepol/cil/src/cil_resolve_ast.c | 38 +++++++++++++++
 libsepol/cil/src/cil_resolve_ast.h |  1 +
 libsepol/cil/src/cil_write_ast.c   | 11 +++++
 libsepol/src/kernel_to_cil.c       | 32 +++++++++++++
 secilc/docs/README.md              |  1 +
 secilc/docs/cil_type_statements.md | 50 ++++++++++++++++++++
 15 files changed, 346 insertions(+)

diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
index 38edcf8e..cc6adb90 100644
--- a/libsepol/cil/src/cil.c
+++ b/libsepol/cil/src/cil.c
@@ -225,6 +225,7 @@ char *CIL_KEY_SRC_CIL;
 char *CIL_KEY_SRC_HLL_LMS;
 char *CIL_KEY_SRC_HLL_LMX;
 char *CIL_KEY_SRC_HLL_LME;
+char *CIL_KEY_SEGREGATEATTRIBUTES;
 
 static void cil_init_keys(void)
 {
@@ -394,6 +395,7 @@ static void cil_init_keys(void)
 	CIL_KEY_SRC_HLL_LMS = cil_strpool_add("lms");
 	CIL_KEY_SRC_HLL_LMX = cil_strpool_add("lmx");
 	CIL_KEY_SRC_HLL_LME = cil_strpool_add("lme");
+	CIL_KEY_SEGREGATEATTRIBUTES = cil_strpool_add("segregateattributes");
 }
 
 void cil_db_init(struct cil_db **db)
@@ -426,6 +428,7 @@ void cil_db_init(struct cil_db **db)
 	cil_list_init(&(*db)->userprefixes, CIL_LIST_ITEM);
 	cil_list_init(&(*db)->selinuxusers, CIL_LIST_ITEM);
 	cil_list_init(&(*db)->names, CIL_LIST_ITEM);
+	cil_list_init(&(*db)->segregateattributes, CIL_LIST_ITEM);
 
 	cil_type_init(&(*db)->selftype);
 	(*db)->selftype->datum.name = CIL_KEY_SELF;
@@ -481,6 +484,7 @@ void cil_db_destroy(struct cil_db **db)
 	cil_list_destroy(&(*db)->userprefixes, CIL_FALSE);
 	cil_list_destroy(&(*db)->selinuxusers, CIL_FALSE);
 	cil_list_destroy(&(*db)->names, CIL_TRUE);
+	cil_list_destroy(&(*db)->segregateattributes, CIL_FALSE);
 
 	cil_destroy_type((*db)->selftype);
 
@@ -1005,6 +1009,9 @@ void cil_destroy_data(void **data, enum cil_flavor flavor)
 	case CIL_SRC_INFO:
 		cil_destroy_src_info(*data);
 		break;
+	case CIL_SEGREGATEATTRIBUTES:
+		cil_destroy_segregateattributes(*data);
+		break;
 	case CIL_OP:
 	case CIL_CONS_OPERAND:
 		break;
@@ -1413,6 +1420,8 @@ const char * cil_node_to_string(struct cil_tree_node *node)
 		return CIL_KEY_CONS_H1;
 	case CIL_CONS_H2:
 		return CIL_KEY_CONS_H2;
+	case CIL_SEGREGATEATTRIBUTES:
+		return CIL_KEY_SEGREGATEATTRIBUTES;
 
 	default:
 		break;
@@ -2904,3 +2913,11 @@ void cil_src_info_init(struct cil_src_info **info)
 	(*info)->hll_line = 0;
 	(*info)->path = NULL;
 }
+
+void cil_segregateattributes_init(struct cil_segregateattributes **sattrs)
+{
+	*sattrs = cil_malloc(sizeof(**sattrs));
+
+	(*sattrs)->str_expr = NULL;
+	(*sattrs)->datum_expr = NULL;
+}
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index 40615db2..0301d739 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -3818,6 +3818,38 @@ exit:
 	return SEPOL_ERR;
 }
 
+static int cil_segregateattributes_to_policydb(policydb_t *pdb, const struct cil_segregateattributes *sattrs)
+{
+	segregate_attributes_rule_t *sattr;
+	struct cil_list_item *curr;
+	type_datum_t *sepol_type;
+	int rc = SEPOL_ERR;
+
+	sattr = cil_malloc(sizeof(segregate_attributes_rule_t));
+	ebitmap_init(&sattr->attrs);
+
+	cil_list_for_each(curr, sattrs->datum_expr) {
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(curr->data), &sepol_type);
+		if (rc != SEPOL_OK) goto exit;
+
+		if (ebitmap_set_bit(&sattr->attrs, sepol_type->s.value - 1, 1)) {
+			goto exit;
+		}
+	}
+
+	sattr->next = pdb->segregate_attributes;
+	pdb->segregate_attributes = sattr;
+
+	return SEPOL_OK;
+
+exit:
+	if (sattr) {
+		ebitmap_destroy(&sattr->attrs);
+		free(sattr);
+	}
+	return rc;
+}
+
 static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args)
 {
 	int rc = SEPOL_OK;
@@ -3960,6 +3992,9 @@ static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args)
 		case CIL_DEFAULTRANGE:
 			rc = cil_defaultrange_to_policydb(pdb, node->data);
 			break;
+		case CIL_SEGREGATEATTRIBUTES:
+			rc = cil_segregateattributes_to_policydb(pdb, node->data);
+			break;
 		default:
 			break;
 		}
@@ -4890,6 +4925,42 @@ exit:
 	return rc;
 }
 
+static int cil_check_segregateattributes(const policydb_t *pdb, int *violation)
+{
+	const segregate_attributes_rule_t *sattr;
+
+	for (sattr = pdb->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_after(&sattr->attrs, second_node, second_bit, first_node, first_bit) {
+				ebitmap_t attr_union;
+				ebitmap_node_t *type_node;
+				unsigned int type_bit;
+
+				if (ebitmap_and(&attr_union, &pdb->attr_type_map[first_bit], &pdb->attr_type_map[second_bit]))
+					return SEPOL_ERR;
+
+				ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) {
+					cil_log(CIL_ERR, "Segregate Attributes violation, type %s associated with attributes %s and %s\n",
+					                 pdb->p_type_val_to_name[type_bit],
+					                 pdb->p_type_val_to_name[first_bit],
+					                 pdb->p_type_val_to_name[second_bit]);
+					*violation = CIL_TRUE;
+				}
+
+				ebitmap_destroy(&attr_union);
+			}
+		}
+	}
+
+	return SEPOL_OK;
+}
+
 static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t class, uint32_t data, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
 {
 	struct cil_classperms *cp;
@@ -5160,6 +5231,10 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p
 		rc = cil_check_neverallows(db, pdb, neverallows, &violation);
 		if (rc != SEPOL_OK) goto exit;
 
+		cil_log(CIL_INFO, "Checking Segregate Attributes\n");
+		rc = cil_check_segregateattributes(pdb, &violation);
+		if (rc != SEPOL_OK) goto exit;
+
 		cil_log(CIL_INFO, "Checking User Bounds\n");
 		rc = bounds_check_users(NULL, pdb);
 		if (rc) {
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
index 4177c9f6..611aade8 100644
--- a/libsepol/cil/src/cil_build_ast.c
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -6164,6 +6164,62 @@ void cil_destroy_src_info(struct cil_src_info *info)
 	free(info);
 }
 
+int cil_gen_segregateattributes(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	size_t syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_segregateattributes *sattrs = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_segregateattributes_init(&sattrs);
+
+	rc = cil_gen_expr(parse_current->next, CIL_TYPEATTRIBUTE, &sattrs->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	/* require at least two attributes */
+	if (sattrs->str_expr->head == sattrs->str_expr->tail) {
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	ast_node->data = sattrs;
+	ast_node->flavor = CIL_SEGREGATEATTRIBUTES;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad segregate attributes declaration");
+	cil_destroy_segregateattributes(sattrs);
+	return rc;
+}
+
+void cil_destroy_segregateattributes(struct cil_segregateattributes *sattrs)
+{
+	if (sattrs == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&sattrs->str_expr, CIL_TRUE);
+	cil_list_destroy(&sattrs->datum_expr, CIL_FALSE);
+
+	free(sattrs);
+}
+
 static int check_for_illegal_statement(struct cil_tree_node *parse_current, struct cil_args_build *args)
 {
 	if (args->tunif != NULL) {
@@ -6455,6 +6511,8 @@ static struct cil_tree_node * parse_statement(struct cil_db *db, struct cil_tree
 		rc = cil_gen_mls(parse_current, new_ast_node);
 	} else if (parse_current->data == CIL_KEY_SRC_INFO) {
 		rc = cil_gen_src_info(parse_current, new_ast_node);
+	} else if (parse_current->data == CIL_KEY_SEGREGATEATTRIBUTES) {
+		rc = cil_gen_segregateattributes(db, parse_current, new_ast_node);
 	} else {
 		cil_log(CIL_ERR, "Error: Unknown keyword %s\n", (char *)parse_current->data);
 		rc = SEPOL_ERR;
diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h
index fd9053ce..d815a22f 100644
--- a/libsepol/cil/src/cil_build_ast.h
+++ b/libsepol/cil/src/cil_build_ast.h
@@ -225,6 +225,8 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no
 void cil_destroy_defaultrange(struct cil_defaultrange *def);
 int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
 void cil_destroy_src_info(struct cil_src_info *info);
+int cil_gen_segregateattributes(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_segregateattributes(struct cil_segregateattributes *sattrs);
 
 int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats);
 void cil_destroy_cats(struct cil_cats *cats);
diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
index 17f05021..e0f3ba4f 100644
--- a/libsepol/cil/src/cil_copy_ast.c
+++ b/libsepol/cil/src/cil_copy_ast.c
@@ -1697,6 +1697,21 @@ static int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *da
 	return SEPOL_OK;
 }
 
+static int cil_copy_segregateattributes(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_segregateattributes *orig = data;
+	struct cil_segregateattributes *new = NULL;
+
+	cil_segregateattributes_init(&new);
+
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
 static int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args)
 {
 	int rc = SEPOL_ERR;
@@ -1990,6 +2005,9 @@ static int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished
 	case CIL_SRC_INFO:
 		copy_func = &cil_copy_src_info;
 		break;
+	case CIL_SEGREGATEATTRIBUTES:
+		copy_func = &cil_copy_segregateattributes;
+		break;
 	default:
 		goto exit;
 	}
diff --git a/libsepol/cil/src/cil_flavor.h b/libsepol/cil/src/cil_flavor.h
index c2f0cee7..ffbd5877 100644
--- a/libsepol/cil/src/cil_flavor.h
+++ b/libsepol/cil/src/cil_flavor.h
@@ -115,6 +115,7 @@ enum cil_flavor {
 	CIL_SRC_INFO,
 	CIL_IBPKEYCON,
 	CIL_IBENDPORTCON,
+	CIL_SEGREGATEATTRIBUTES,
 
 /*
  *          boolean  constraint  set  catset
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
index a7604762..e22c2f87 100644
--- a/libsepol/cil/src/cil_internal.h
+++ b/libsepol/cil/src/cil_internal.h
@@ -242,6 +242,7 @@ extern char *CIL_KEY_SRC_CIL;
 extern char *CIL_KEY_SRC_HLL_LMS;
 extern char *CIL_KEY_SRC_HLL_LMX;
 extern char *CIL_KEY_SRC_HLL_LME;
+extern char *CIL_KEY_SEGREGATEATTRIBUTES;
 
 /*
 	Symbol Table Array Indices
@@ -309,6 +310,7 @@ struct cil_db {
 	struct cil_list *userprefixes;
 	struct cil_list *selinuxusers;
 	struct cil_list *names;
+	struct cil_list *segregateattributes;
 	int num_types_and_attrs;
 	int num_classes;
 	int num_cats;
@@ -975,6 +977,11 @@ struct cil_src_info {
 	char *path;
 };
 
+struct cil_segregateattributes {
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
 void cil_db_init(struct cil_db **db);
 void cil_db_destroy(struct cil_db **db);
 
@@ -1085,5 +1092,6 @@ void cil_mls_init(struct cil_mls **mls);
 void cil_src_info_init(struct cil_src_info **info);
 void cil_userattribute_init(struct cil_userattribute **attribute);
 void cil_userattributeset_init(struct cil_userattributeset **attrset);
+void cil_segregateattributes_init(struct cil_segregateattributes **sattrs);
 
 #endif
diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
index 7c543c47..36f6780d 100644
--- a/libsepol/cil/src/cil_policy.c
+++ b/libsepol/cil/src/cil_policy.c
@@ -69,6 +69,7 @@ enum cil_statement_list {
 	CIL_LIST_USER,
 	CIL_LIST_CONSTRAINT,
 	CIL_LIST_VALIDATETRANS,
+	CIL_LIST_SEGREGATEATTRIBUTES,
 	CIL_LIST_NUM_LISTS
 };
 
@@ -168,6 +169,9 @@ static int __cil_gather_statements_helper(struct cil_tree_node *node, uint32_t *
 	case CIL_VALIDATETRANS:
 		kind = CIL_LIST_VALIDATETRANS;
 		break;
+	case CIL_SEGREGATEATTRIBUTES:
+		kind = CIL_LIST_SEGREGATEATTRIBUTES;
+		break;
 	default:
 		break;
 	}
@@ -1911,6 +1915,27 @@ static void cil_devicetreecons_to_policy(FILE *out, struct cil_sort *devicetreec
 	}
 }
 
+static void cil_segregateattributes_to_policy(FILE *out, struct cil_list *sattrs_list)
+{
+	struct cil_list_item *curr_sattrs, *curr_attr;
+	struct cil_segregateattributes *sattrs;
+	int first = 1;
+
+	cil_list_for_each(curr_sattrs, sattrs_list) {
+		sattrs = curr_sattrs->data;
+		fprintf(out, "segregate_attriutes ");
+		cil_list_for_each(curr_attr, sattrs->datum_expr) {
+			if (!first) {
+				first = 0;
+			} else {
+				fprintf(out, ", ");
+			}
+			fprintf(out, "%s", DATUM(curr_attr->data)->fqn);
+		}
+		fprintf(out, ";\n");
+	}
+}
+
 void cil_gen_policy(FILE *out, struct cil_db *db)
 {
 	unsigned i;
@@ -1956,6 +1981,7 @@ void cil_gen_policy(FILE *out, struct cil_db *db)
 	cil_typebounds_to_policy(out, lists[CIL_LIST_TYPE]);
 	cil_typeattributes_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEATTRIBUTE]);
 	cil_te_rules_to_policy(out, head, db->mls);
+	cil_segregateattributes_to_policy(out, db->segregateattributes);
 
 	cil_roles_to_policy(out, lists[CIL_LIST_ROLE]);
 	cil_role_types_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_TYPE]);
diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c
index 0864d7ef..c5ac83c8 100644
--- a/libsepol/cil/src/cil_reset_ast.c
+++ b/libsepol/cil/src/cil_reset_ast.c
@@ -475,6 +475,11 @@ static void cil_reset_booleanif(struct cil_booleanif *bif)
 	cil_list_destroy(&bif->datum_expr, CIL_FALSE);
 }
 
+static void cil_reset_segregateattributes(struct cil_segregateattributes *sattrs)
+{
+	cil_list_destroy(&sattrs->datum_expr, CIL_FALSE);
+}
+
 static int __cil_reset_node(struct cil_tree_node *node,  __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args)
 {
 	switch (node->flavor) {
@@ -630,6 +635,9 @@ static int __cil_reset_node(struct cil_tree_node *node,  __attribute__((unused))
 	case CIL_BOOLEANIF:
 		cil_reset_booleanif(node->data);
 		break;
+	case CIL_SEGREGATEATTRIBUTES:
+		cil_reset_segregateattributes(node->data);
+		break;
 	case CIL_TUNABLEIF:
 	case CIL_CALL:
 		break; /* Not effected by optional block disabling */
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
index f5e22c97..36a96199 100644
--- a/libsepol/cil/src/cil_resolve_ast.c
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -3265,6 +3265,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc
 		sym_index = CIL_SYM_TUNABLES;
 		break;
 	case CIL_TYPE:
+	case CIL_TYPEATTRIBUTE:
 		sym_index = CIL_SYM_TYPES;
 		break;
 	case CIL_ROLE:
@@ -3312,6 +3313,13 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc
 			} else {
 				if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) {
 					cil_type_used(res_datum, CIL_ATTR_CONSTRAINT);
+				} else if (expr_type == CIL_SEGREGATEATTRIBUTES) {
+					if (FLAVOR(res_datum) != CIL_TYPEATTRIBUTE) {
+						cil_tree_log(parent, CIL_ERR, "Type or type alias not supported in segregate attributes declaration");
+						rc = SEPOL_ERR;
+						goto exit;
+					}
+					cil_type_used(res_datum, CIL_ATTR_NEVERALLOW);
 				}
 				cil_list_append(*datum_expr, CIL_DATUM, res_datum);
 			}
@@ -3508,6 +3516,33 @@ exit:
 	return rc;
 }
 
+int cil_resolve_segregateattributes(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_segregateattributes *sattrs = current->data;
+	struct cil_list_item *first, *second;
+	int rc;
+
+	rc = cil_resolve_expr(CIL_SEGREGATEATTRIBUTES, sattrs->str_expr, &sattrs->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_list_for_each(first, sattrs->datum_expr) {
+		for (second = first->next; second; second = second->next) {
+			if (first->data == second->data) {
+				cil_tree_log(current, CIL_ERR, "Repeated attribute in segregate attributes declaration");
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
 /*
  * Degenerate inheritance leads to exponential growth of the policy
  * It can take many forms, but here is one example.
@@ -3888,6 +3923,9 @@ static int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
 		case CIL_USERATTRIBUTESET:
 			rc = cil_resolve_userattributeset(node, args);
 			break;
+		case CIL_SEGREGATEATTRIBUTES:
+			rc = cil_resolve_segregateattributes(node, args);
+			break;
 		default:
 			break;
 		}
diff --git a/libsepol/cil/src/cil_resolve_ast.h b/libsepol/cil/src/cil_resolve_ast.h
index 1d971fd6..31594954 100644
--- a/libsepol/cil/src/cil_resolve_ast.h
+++ b/libsepol/cil/src/cil_resolve_ast.h
@@ -96,6 +96,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc
 int cil_resolve_boolif(struct cil_tree_node *current, void *extra_args);
 int cil_evaluate_expr(struct cil_list *datum_expr, uint16_t *result);
 int cil_resolve_tunif(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_segregateattributes(struct cil_tree_node *current, void *extra_args);
 
 int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current);
 int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_index sym_index, void *extra_args, struct cil_symtab_datum **datum);
diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c
index b75784ef..d0fb555b 100644
--- a/libsepol/cil/src/cil_write_ast.c
+++ b/libsepol/cil/src/cil_write_ast.c
@@ -1474,7 +1474,18 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
 		fprintf(out, "(ipaddr %s %s)\n", datum_to_str(&ipaddr->datum), buf);
 		break;
 	}
+	case CIL_SEGREGATEATTRIBUTES: {
+		struct cil_segregateattributes *sattrs = node->data;
+		fprintf(out, "(segregateattributes ");
+		if (sattrs->datum_expr)
+			write_expr(out, sattrs->datum_expr);
+		else
+			write_expr(out, sattrs->str_expr);
+		fprintf(out, ")\n");
+		break;
+	}
 	default :
+		cil_log(CIL_ERR, "Unsupported flavor: %d\n", node->flavor);
 		fprintf(out, "(<?RULE:%s>)\n", cil_node_to_string(node));
 		break;
 	}
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index 9128ac55..4b99208d 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -1906,6 +1906,33 @@ static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
 	return 0;
 }
 
+static int write_segregate_attributes_to_cil(FILE *out, const struct policydb *pdb)
+{
+	const segregate_attributes_rule_t *sattr;
+
+	for (sattr = pdb->segregate_attributes; sattr; sattr = sattr->next) {
+		struct ebitmap_node *node;
+		unsigned int bit;
+		int first = 1;
+
+		sepol_printf(out, "(segregateattributes (");
+
+		ebitmap_for_each_positive_bit(&sattr->attrs, node, bit) {
+			if (first) {
+				first = 0;
+			} else {
+				sepol_printf(out, " ");
+			}
+
+			sepol_printf(out, "%s", pdb->p_type_val_to_name[bit - 1]);
+		}
+
+		sepol_printf(out, "))\n");
+	}
+
+	return 0;
+}
+
 static int write_filename_trans_rules_to_cil(FILE *out, struct policydb *pdb)
 {
 	struct map_filename_trans_args args;
@@ -3329,6 +3356,11 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb)
 		goto exit;
 	}
 
+	rc = write_segregate_attributes_to_cil(out, pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
 	rc = write_filename_trans_rules_to_cil(out, pdb);
 	if (rc != 0) {
 		goto exit;
diff --git a/secilc/docs/README.md b/secilc/docs/README.md
index efab2a71..8f584019 100644
--- a/secilc/docs/README.md
+++ b/secilc/docs/README.md
@@ -132,6 +132,7 @@ CIL (Common Intermediate Language)
   * [typemember](cil_type_statements.md#typemember)
   * [typetransition](cil_type_statements.md#typetransition)
   * [typepermissive](cil_type_statements.md#typepermissive)
+  * [segregateattributes](cil_type_statements.md#segregateattributes)
 
 * [User Statements](cil_user_statements.md#user-statements)
   * [user](cil_user_statements.md#user)
diff --git a/secilc/docs/cil_type_statements.md b/secilc/docs/cil_type_statements.md
index 19438417..56533eea 100644
--- a/secilc/docs/cil_type_statements.md
+++ b/secilc/docs/cil_type_statements.md
@@ -601,3 +601,53 @@ This example will allow SELinux to run the `healthd.process` domain in permissiv
         (allow ...)
     )
 ```
+
+segregateattributes
+-------------------
+
+Libsepol and secilc version 3.5 introduced the segregateattributes statement
+to mark two or more type attributes mutual exclusive. This is a compiler
+enforced action that will stop compilation until the offending associations
+are modified.
+
+Note that these constraints can be over-ridden by the CIL compiler command
+line parameter `-N` or `--disable-neverallow` flags.
+
+**Statement definition:**
+
+```secil
+    (segregateattributes (typeattribute_id typeattribute_id...))
+```
+
+**Where:**
+
+<table>
+<colgroup>
+<col width="27%" />
+<col width="72%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td align="left"><p><code>segregateattributes</code></p></td>
+<td align="left"><p>The <code>segregateattributes</code> keyword.</p></td>
+</tr>
+<tr class="even">
+<td align="left"><p><code>typeattribute_id</code></p></td>
+<td align="left"><p>At least two previously declared <code>typeattribute</code> identifier.</p>
+<p>Note that the same <code>typeattribute</code> identifier must not be repeated.</p></td>
+</tr>
+</tbody>
+</table>
+
+**Example:**
+
+This example will not compile as `type_1` is associated with type attributes `attr_1` and `attr_2`:
+
+```secil
+    (type type_1)
+    (typeattribute attr_1)
+    (typeattribute attr_2)
+    (typeattributeset attr_1 (type_1))
+    (typeattributeset attr_2 (type_1))
+    (segregateattributes (attr_1 attr_2))
+```
-- 
2.36.1


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

* [PATCH v3 7/8] secilc: run tests against development version of libsepol
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
                   ` (4 preceding siblings ...)
  2022-07-21 15:05 ` [PATCH v3 6/8] libsepol/cil: add support " Christian Göttsche
@ 2022-07-21 15:05 ` Christian Göttsche
  2022-08-08 15:20   ` James Carter
  2022-07-21 15:05 ` [PATCH v3 8/8] secilc: include segregate attributes in tests Christian Göttsche
  2022-08-08 15:01 ` [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c James Carter
  7 siblings, 1 reply; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 UTC (permalink / raw)
  To: selinux

Since secilc is dynamically linked against libsepol do not run tests
against the system version of libsepol to support new features currently
in development.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 secilc/Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/secilc/Makefile b/secilc/Makefile
index 94be0481..543df43b 100644
--- a/secilc/Makefile
+++ b/secilc/Makefile
@@ -34,8 +34,8 @@ $(SECILC): $(SECILC_OBJS)
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
 
 test: $(SECILC)
-	./$(SECILC) test/policy.cil
-	./$(SECILC) -c $(POL_VERS) -O -M 1 -f /dev/null -o opt-actual.bin test/opt-input.cil
+	env LD_LIBRARY_PATH="$(DESTDIR)/lib:$(DESTDIR)/usr/lib" ./$(SECILC) test/policy.cil
+	env LD_LIBRARY_PATH="$(DESTDIR)/lib:$(DESTDIR)/usr/lib" ./$(SECILC) -c $(POL_VERS) -O -M 1 -f /dev/null -o opt-actual.bin test/opt-input.cil
 	$(CHECKPOLICY) -b -C -M -o opt-actual.cil opt-actual.bin >/dev/null
 	$(DIFF) test/opt-expected.cil opt-actual.cil
 
-- 
2.36.1


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

* [PATCH v3 8/8] secilc: include segregate attributes in tests
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
                   ` (5 preceding siblings ...)
  2022-07-21 15:05 ` [PATCH v3 7/8] secilc: run tests against development version of libsepol Christian Göttsche
@ 2022-07-21 15:05 ` Christian Göttsche
  2022-08-08 15:01 ` [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c James Carter
  7 siblings, 0 replies; 17+ messages in thread
From: Christian Göttsche @ 2022-07-21 15:05 UTC (permalink / raw)
  To: selinux

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 secilc/test/policy.cil | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/secilc/test/policy.cil b/secilc/test/policy.cil
index e6b78618..4e1d6b61 100644
--- a/secilc/test/policy.cil
+++ b/secilc/test/policy.cil
@@ -118,13 +118,16 @@
 	(typeattribute foo_type)
 	(typeattribute bar_type)
 	(typeattribute baz_type)
+	(typeattribute bad_type)
 	(typeattribute not_bad_type)
 	(typeattributeset exec_type (or bin_t kernel_t))
 	(typeattributeset foo_type (and exec_type kernel_t))
 	(typeattributeset bar_type (xor exec_type foo_type))
 	(typeattributeset baz_type (not bin_t))
 	(typeattributeset baz_type (and exec_type (and bar_type bin_t)))
+	(typeattributeset bad_type (bad_t))
 	(typeattributeset not_bad_type (not bad_t))
+	(segregateattributes (bad_type not_bad_type))
 	(typealias sbin_t)
 	(typealiasactual sbin_t bin_t)
 	(typepermissive device_t) 
-- 
2.36.1


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

* Re: [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c
  2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
                   ` (6 preceding siblings ...)
  2022-07-21 15:05 ` [PATCH v3 8/8] secilc: include segregate attributes in tests Christian Göttsche
@ 2022-08-08 15:01 ` James Carter
  2022-08-09 15:22   ` James Carter
  7 siblings, 1 reply; 17+ messages in thread
From: James Carter @ 2022-08-08 15:01 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Thu, Jul 21, 2022 at 11:11 AM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> 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>

Acked-by: James Carter <jwcart2@gmail.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	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 2/8] libsepol: add ebitmap iterator wrapper with startnode
  2022-07-21 15:05 ` [PATCH v3 2/8] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
@ 2022-08-08 15:04   ` James Carter
  0 siblings, 0 replies; 17+ messages in thread
From: James Carter @ 2022-08-08 15:04 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Thu, Jul 21, 2022 at 11:11 AM 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>
> ---
> v2:
>    * use _after suffix
>    * reorder parameters
> ---
>  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..4696805f 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_after(e, n, bit, startnode, startbit) \
> +       n = startnode; \
> +       for (bit = ebitmap_next(&n, startbit); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
> +

It would be better to only use one statement:

for (n = startnode, bit = ebitmap_next(&n, startbit); ...

Thanks,
Jim


> +#define ebitmap_for_each_positive_bit_after(e, n, bit, startnode, startbit) \
> +       ebitmap_for_each_bit_after(e, n, bit, startnode, startbit) 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	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 7/8] secilc: run tests against development version of libsepol
  2022-07-21 15:05 ` [PATCH v3 7/8] secilc: run tests against development version of libsepol Christian Göttsche
@ 2022-08-08 15:20   ` James Carter
  0 siblings, 0 replies; 17+ messages in thread
From: James Carter @ 2022-08-08 15:20 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Thu, Jul 21, 2022 at 11:11 AM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Since secilc is dynamically linked against libsepol do not run tests
> against the system version of libsepol to support new features currently
> in development.
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
>  secilc/Makefile | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/secilc/Makefile b/secilc/Makefile
> index 94be0481..543df43b 100644
> --- a/secilc/Makefile
> +++ b/secilc/Makefile
> @@ -34,8 +34,8 @@ $(SECILC): $(SECILC_OBJS)
>         $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
>
>  test: $(SECILC)
> -       ./$(SECILC) test/policy.cil
> -       ./$(SECILC) -c $(POL_VERS) -O -M 1 -f /dev/null -o opt-actual.bin test/opt-input.cil
> +       env LD_LIBRARY_PATH="$(DESTDIR)/lib:$(DESTDIR)/usr/lib" ./$(SECILC) test/policy.cil
> +       env LD_LIBRARY_PATH="$(DESTDIR)/lib:$(DESTDIR)/usr/lib" ./$(SECILC) -c $(POL_VERS) -O -M 1 -f /dev/null -o opt-actual.bin test/opt-input.cil
>         $(CHECKPOLICY) -b -C -M -o opt-actual.cil opt-actual.bin >/dev/null
>         $(DIFF) test/opt-expected.cil opt-actual.cil
>

This assumes that LIBDIR and SHLIBDIR were not used.

The README.md file says to use the following for tests:

DESTDIR=~/obj ./scripts/env_use_destdir make test

and that works for secilc as well.

Jim


> --
> 2.36.1
>

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

* Re: [PATCH v3 3/8] libsepol: add compile-time constraint for mutual exclusive attributes
  2022-07-21 15:05 ` [PATCH v3 3/8] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
@ 2022-08-08 17:02   ` James Carter
  0 siblings, 0 replies; 17+ messages in thread
From: James Carter @ 2022-08-08 17:02 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Thu, Jul 21, 2022 at 11:11 AM 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 violation, 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 violation, type sysctl_fs_t associated with attributes sysctl_type and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type sysctl_t associated with attributes sysctl_type and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type virt_content_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type initrc_devpts_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type qemu_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type user_devpts_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type cardmgr_dev_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type bootloader_tmp_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type xen_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type svirt_prot_exec_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type xen_devpts_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type svirt_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type virt_image_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type container_file_t associated with attributes device_node and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type cpu_online_t associated with attributes sysfs_types and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type sysfs_t associated with attributes sysfs_types and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type dockerc_t associated with attributes domain and file_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type proc_t associated with attributes file_type and proc_type
>         libsepol.check_segregate_attributes: Segregate Attributes violation, type proc_xen_t associated with attributes file_type and proc_type
>
>     libsepol.check_assertions: 20 Segregate Attributes failures occurred
>
> Closes: https://github.com/SELinuxProject/selinux/issues/42
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
> v3:
>    - drop source location information:
>      this information was already lost for binary modular policies and
>      CIL policies; also typeattribute statements have none and the few
>      segregate_attributes statements can be easily grepped
>    - misc renaming
> v2:
>    rebase onto _after suffix change


I am not completely sold on this for a couple of reasons.
1) Neverallow rules express actual security goals.
2) Should we really keep adding more to the modular policy and
policy.conf languages?
3) This can already be tested in CIL (but not as cleanly)
  (typeattribute disjoint_types)
  (typeattributeset disjoint_types (and attr1 attr2))
  (allow disjoint_types self (process (transition)))
  (neverallow disjoint_types self (process (transition)))

I would prefer "disjoint" to "segegrate" as well.

Thanks,
Jim

> ---
>  libsepol/include/sepol/policydb/policydb.h | 15 ++++-
>  libsepol/src/assertion.c                   | 57 +++++++++++++---
>  libsepol/src/expand.c                      | 45 ++++++++++++-
>  libsepol/src/kernel_to_conf.c              | 38 ++++++++++-
>  libsepol/src/link.c                        | 44 +++++++++++++
>  libsepol/src/policydb.c                    | 76 ++++++++++++++++++++++
>  libsepol/src/policydb_validate.c           | 29 +++++++++
>  libsepol/src/write.c                       | 34 +++++++++-
>  8 files changed, 325 insertions(+), 13 deletions(-)
>
> diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
> index de0068a6..d62d030c 100644
> --- a/libsepol/include/sepol/policydb/policydb.h
> +++ b/libsepol/include/sepol/policydb/policydb.h
> @@ -192,6 +192,12 @@ typedef struct type_datum {
>         uint32_t bounds;        /* bounds type, if exist */
>  } type_datum_t;
>
> +/* Mutual exclusive attributes */
> +typedef struct segregate_attributes_rule {
> +       ebitmap_t attrs;        /* mutual exclusive attributes */
> +       struct segregate_attributes_rule *next;
> +} segregate_attributes_rule_t;
> +
>  /*
>   * Properties of type_datum
>   * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
> @@ -605,6 +611,10 @@ 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).
> +          stored as linked list */
> +       segregate_attributes_rule_t *segregate_attributes;
> +
>         unsigned policyvers;
>
>         unsigned handle_unknown;
> @@ -696,6 +706,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_attributes_rule_init(segregate_attributes_rule_t * x);
> +extern void segregate_attributes_rule_destroy(segregate_attributes_rule_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 +795,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_SEGREGATE_ATTRIBUTES      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_SEGREGATE_ATTRIBUTES
>
>  #define POLICYDB_CONFIG_MLS    1
>
> diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c
> index 161874c3..a6dda570 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,44 @@ int check_assertion(policydb_t *p, avrule_t *avrule)
>         return rc;
>  }
>
> +static int check_segregate_attributes(sepol_handle_t *handle, const policydb_t *p)
> +{
> +       const segregate_attributes_rule_t *sattr;
> +       int errors = 0, rc;
> +
> +       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_after(&sattr->attrs, second_node, second_bit, first_node, first_bit) {
> +                               ebitmap_t attr_union;
> +                               ebitmap_node_t *type_node;
> +                               unsigned int type_bit;
> +
> +                               rc = ebitmap_and(&attr_union, &p->attr_type_map[first_bit], &p->attr_type_map[second_bit]);
> +                               if (rc < 0)
> +                                       return rc;
> +
> +                               ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) {
> +                                       ERR(handle, "Segregate Attributes violation, 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)
>  {
> @@ -542,13 +580,6 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
>         avrule_t *a;
>         unsigned long errors = 0;
>
> -       if (!avrules) {
> -               /* Since assertions are stored in avrules, if it is NULL
> -                  there won't be any to check. This also prevents an invalid
> -                  free if the avtabs are never initialized */
> -               return 0;
> -       }
> -
>         for (a = avrules; a != NULL; a = a->next) {
>                 if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
>                         continue;
> @@ -570,5 +601,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 Attributes failures occurred", rc);
> +               errors += rc;
> +       }
> +
>         return errors ? -1 : 0;
>  }
> diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
> index 8d19850e..6f52d1ff 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,45 @@ static int genfs_copy(expand_state_t * state)
>         return 0;
>  }
>
> +static int segregate_attributes_copy(expand_state_t *state)
> +{
> +       const segregate_attributes_rule_t *old;
> +       segregate_attributes_rule_t *list = NULL;
> +
> +       for (old = state->base->segregate_attributes; old; old = old->next) {
> +               segregate_attributes_rule_t *new;
> +
> +               new = malloc(sizeof(segregate_attributes_rule_t));
> +               if (!new) {
> +                       ERR(state->handle, "Out of memory!");
> +                       return -1;
> +               }
> +
> +               segregate_attributes_rule_init(new);
> +
> +               if (map_ebitmap(&old->attrs, &new->attrs, state->typemap)) {
> +                       ERR(state->handle, "out of memory");
> +                       ebitmap_destroy(&new->attrs);
> +                       free(new);
> +                       return -1;
> +               }
> +
> +               if (list)
> +                       list->next = new;
> +               else {
> +                       if (state->out->segregate_attributes) {
> +                               segregate_attributes_rule_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 +3212,10 @@ int expand_module(sepol_handle_t * handle,
>         if (genfs_copy(&state))
>                 goto cleanup;
>
> +       /* copy segregate attributes */
> +       if (segregate_attributes_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/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> index 63dffd9b..f119d572 100644
> --- a/libsepol/src/kernel_to_conf.c
> +++ b/libsepol/src/kernel_to_conf.c
> @@ -1839,6 +1839,33 @@ exit:
>         return rc;
>  }
>
> +static int write_segregate_attributes_to_conf(FILE *out, const struct policydb *pdb)
> +{
> +       const segregate_attributes_rule_t *sattr;
> +
> +       for (sattr = pdb->segregate_attributes; sattr; sattr = sattr->next) {
> +               struct ebitmap_node *node;
> +               unsigned int bit;
> +               int first = 1;
> +
> +               sepol_printf(out, "segregate_attributes ");
> +
> +               ebitmap_for_each_positive_bit(&sattr->attrs, node, bit) {
> +                       if (first) {
> +                               first = 0;
> +                       } else {
> +                               sepol_printf(out, ", ");
> +                       }
> +
> +                       sepol_printf(out, "%s", pdb->p_type_val_to_name[bit - 1]);
> +               }
> +
> +               sepol_printf(out, ";\n");
> +       }
> +
> +       return 0;
> +}
> +
>  struct map_filename_trans_args {
>         struct policydb *pdb;
>         struct strs *strs;
> @@ -3200,7 +3227,16 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
>         if (rc != 0) {
>                 goto exit;
>         }
> -       write_filename_trans_rules_to_conf(out, pdb);
> +
> +       rc = write_segregate_attributes_to_conf(out, pdb);
> +       if (rc != 0) {
> +               goto exit;
> +       }
> +
> +       rc = write_filename_trans_rules_to_conf(out, pdb);
> +       if (rc != 0) {
> +               goto exit;
> +       }
>
>         if (pdb->mls) {
>                 rc = write_range_trans_rules_to_conf(out, pdb);
> diff --git a/libsepol/src/link.c b/libsepol/src/link.c
> index cbe4cea4..1650a9c0 100644
> --- a/libsepol/src/link.c
> +++ b/libsepol/src/link.c
> @@ -1857,6 +1857,45 @@ 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_attributes_rule_t *src_sattr;
> +       segregate_attributes_rule_t *list = NULL;
> +
> +       for (src_sattr = module->policy->segregate_attributes; src_sattr; src_sattr = src_sattr->next) {
> +               segregate_attributes_rule_t *new_sattr;
> +
> +               new_sattr = malloc(sizeof(segregate_attributes_rule_t));
> +               if (!new_sattr) {
> +                       ERR(state->handle, "Out of memory!");
> +                       return -1;
> +               }
> +
> +               segregate_attributes_rule_init(new_sattr);
> +
> +               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;
> +               }
> +
> +               if (list)
> +                       list->next = new_sattr;
> +               else {
> +                       if (state->base->segregate_attributes) {
> +                               segregate_attributes_rule_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 +1930,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..9dbb9f44 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_SEGREGATE_ATTRIBUTES,
> +        .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_SEGREGATE_ATTRIBUTES,
> +        .sym_num = SYM_NUM,
> +        .ocon_num = 0,
> +        .target_platform = SEPOL_TARGET_SELINUX,
> +       },
>  };
>
>  #if 0
> @@ -760,6 +774,20 @@ void avrule_list_destroy(avrule_t * x)
>         }
>  }
>
> +void segregate_attributes_rule_init(segregate_attributes_rule_t * x)
> +{
> +       ebitmap_init(&x->attrs);
> +       x->next = NULL;
> +}
> +
> +
> +void segregate_attributes_rule_destroy(segregate_attributes_rule_t * x)
> +{
> +       if (!x)
> +               return;
> +       ebitmap_destroy(&x->attrs);
> +}
> +
>  /*
>   * 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 +1520,7 @@ void policydb_destroy(policydb_t * p)
>         unsigned int i;
>         role_allow_t *ra, *lra = NULL;
>         role_trans_t *tr, *ltr = NULL;
> +       segregate_attributes_rule_t *sattr, *sattr_next;
>
>         if (!p)
>                 return;
> @@ -1585,6 +1614,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_attributes_rule_destroy(sattr);
> +               free(sattr);
> +       }
> +
>         return;
>  }
>
> @@ -4174,6 +4209,41 @@ 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_attributes_rule_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_attributes_rule_t *sattr;
> +
> +               sattr = malloc(sizeof(segregate_attributes_rule_t));
> +               if (!sattr)
> +                       return -1;
> +
> +               segregate_attributes_rule_init(sattr);
> +
> +               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 +4640,12 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
>                 }
>         }
>
> +       if (p->policyvers >= MOD_POLICYDB_VERSION_SEGREGATE_ATTRIBUTES &&
> +           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..6331c3ce 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_attributes_rule_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 attributes 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 a9fdf93a..81323df9 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;
> @@ -2191,6 +2191,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_attributes_rule_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
> @@ -2413,5 +2437,11 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
>                 }
>         }
>
> +       if (p->policyvers >= MOD_POLICYDB_VERSION_SEGREGATE_ATTRIBUTES &&
> +           p->policy_type != POLICY_KERN) {
> +               if (segregate_attributes_write(p, fp))
> +                       return POLICYDB_ERROR;
> +       }
> +
>         return POLICYDB_SUCCESS;
>  }
> --
> 2.36.1
>

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

* Re: [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes
  2022-07-21 15:05 ` [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes Christian Göttsche
@ 2022-08-08 17:09   ` James Carter
  2023-08-11 16:38     ` Christian Göttsche
  0 siblings, 1 reply; 17+ messages in thread
From: James Carter @ 2022-08-08 17:09 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Thu, Jul 21, 2022 at 11:11 AM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> 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 | 66 +++++++++++++++++++++++++++++++++++++
>  checkpolicy/policy_define.h |  1 +
>  checkpolicy/policy_parse.y  |  5 +++
>  checkpolicy/policy_scan.l   |  2 ++
>  4 files changed, 74 insertions(+)
>
> diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
> index 8bf36859..cf6fbf08 100644
> --- a/checkpolicy/policy_define.c
> +++ b/checkpolicy/policy_define.c
> @@ -1220,6 +1220,72 @@ exit:
>         return rc;
>  }
>
> +int define_segregate_attributes(void)
> +{
> +       char *id = NULL;
> +       segregate_attributes_rule_t *sattr = NULL;
> +       int rc = -1;
> +
> +       if (pass == 1) {
> +               while ((id = queue_remove(id_queue)))
> +                       free(id);
> +               return 0;
> +       }
> +
> +       sattr = malloc(sizeof(segregate_attributes_rule_t));
> +       if (!sattr) {
> +               yyerror("Out of memory!");
> +               goto exit;
> +       }
> +
> +       ebitmap_init(&sattr->attrs);
> +
> +       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;
> +               }
> +

It seems like it would be useful to check a type, so an error would be
given if the type is associated with the attribute.

> +               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) {
> +               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;}
> +

I don't see the need for comparing more than two at a time.

Something like:
disjoint_types attr1 attr2;

Thanks,
Jim

                       ;
>  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	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 6/8] libsepol/cil: add support for segregate attributes
  2022-07-21 15:05 ` [PATCH v3 6/8] libsepol/cil: add support " Christian Göttsche
@ 2022-08-08 17:15   ` James Carter
  0 siblings, 0 replies; 17+ messages in thread
From: James Carter @ 2022-08-08 17:15 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Thu, Jul 21, 2022 at 11:11 AM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Support the compile time constraint with the following syntax:
>
>     (segregateattributes (attr1 attr2 [...]))

Not a list. The vast majority of the cases are going to be that a type
can be either one or another.

(typesdisjoint attr1 attr2)

Keep it simple.

>
> and reports like:
>
>     ...
>     Qualifying Names
>     Compile post process
>     Building policy binary
>     Checking Neverallows
>     Checking Segregate Attributes
>     Segregate Attributes violation, type test_type associated with attributes attr1 attr2
>     Checking User Bounds
>     Checking Role Bounds
>     Checking Type Bounds
>     Failed to generate binary
>     Failed to build policydb
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
>  libsepol/cil/src/cil.c             | 17 +++++++
>  libsepol/cil/src/cil_binary.c      | 75 ++++++++++++++++++++++++++++++
>  libsepol/cil/src/cil_build_ast.c   | 58 +++++++++++++++++++++++
>  libsepol/cil/src/cil_build_ast.h   |  2 +
>  libsepol/cil/src/cil_copy_ast.c    | 18 +++++++
>  libsepol/cil/src/cil_flavor.h      |  1 +
>  libsepol/cil/src/cil_internal.h    |  8 ++++
>  libsepol/cil/src/cil_policy.c      | 26 +++++++++++
>  libsepol/cil/src/cil_reset_ast.c   |  8 ++++
>  libsepol/cil/src/cil_resolve_ast.c | 38 +++++++++++++++
>  libsepol/cil/src/cil_resolve_ast.h |  1 +
>  libsepol/cil/src/cil_write_ast.c   | 11 +++++
>  libsepol/src/kernel_to_cil.c       | 32 +++++++++++++
>  secilc/docs/README.md              |  1 +
>  secilc/docs/cil_type_statements.md | 50 ++++++++++++++++++++
>  15 files changed, 346 insertions(+)
>
> diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
> index 38edcf8e..cc6adb90 100644
> --- a/libsepol/cil/src/cil.c
> +++ b/libsepol/cil/src/cil.c
> @@ -225,6 +225,7 @@ char *CIL_KEY_SRC_CIL;
>  char *CIL_KEY_SRC_HLL_LMS;
>  char *CIL_KEY_SRC_HLL_LMX;
>  char *CIL_KEY_SRC_HLL_LME;
> +char *CIL_KEY_SEGREGATEATTRIBUTES;
>
>  static void cil_init_keys(void)
>  {
> @@ -394,6 +395,7 @@ static void cil_init_keys(void)
>         CIL_KEY_SRC_HLL_LMS = cil_strpool_add("lms");
>         CIL_KEY_SRC_HLL_LMX = cil_strpool_add("lmx");
>         CIL_KEY_SRC_HLL_LME = cil_strpool_add("lme");
> +       CIL_KEY_SEGREGATEATTRIBUTES = cil_strpool_add("segregateattributes");
>  }
>
>  void cil_db_init(struct cil_db **db)
> @@ -426,6 +428,7 @@ void cil_db_init(struct cil_db **db)
>         cil_list_init(&(*db)->userprefixes, CIL_LIST_ITEM);
>         cil_list_init(&(*db)->selinuxusers, CIL_LIST_ITEM);
>         cil_list_init(&(*db)->names, CIL_LIST_ITEM);
> +       cil_list_init(&(*db)->segregateattributes, CIL_LIST_ITEM);
>
>         cil_type_init(&(*db)->selftype);
>         (*db)->selftype->datum.name = CIL_KEY_SELF;
> @@ -481,6 +484,7 @@ void cil_db_destroy(struct cil_db **db)
>         cil_list_destroy(&(*db)->userprefixes, CIL_FALSE);
>         cil_list_destroy(&(*db)->selinuxusers, CIL_FALSE);
>         cil_list_destroy(&(*db)->names, CIL_TRUE);
> +       cil_list_destroy(&(*db)->segregateattributes, CIL_FALSE);
>
>         cil_destroy_type((*db)->selftype);
>
> @@ -1005,6 +1009,9 @@ void cil_destroy_data(void **data, enum cil_flavor flavor)
>         case CIL_SRC_INFO:
>                 cil_destroy_src_info(*data);
>                 break;
> +       case CIL_SEGREGATEATTRIBUTES:
> +               cil_destroy_segregateattributes(*data);
> +               break;
>         case CIL_OP:
>         case CIL_CONS_OPERAND:
>                 break;
> @@ -1413,6 +1420,8 @@ const char * cil_node_to_string(struct cil_tree_node *node)
>                 return CIL_KEY_CONS_H1;
>         case CIL_CONS_H2:
>                 return CIL_KEY_CONS_H2;
> +       case CIL_SEGREGATEATTRIBUTES:
> +               return CIL_KEY_SEGREGATEATTRIBUTES;
>
>         default:
>                 break;
> @@ -2904,3 +2913,11 @@ void cil_src_info_init(struct cil_src_info **info)
>         (*info)->hll_line = 0;
>         (*info)->path = NULL;
>  }
> +
> +void cil_segregateattributes_init(struct cil_segregateattributes **sattrs)
> +{
> +       *sattrs = cil_malloc(sizeof(**sattrs));
> +
> +       (*sattrs)->str_expr = NULL;
> +       (*sattrs)->datum_expr = NULL;
> +}
> diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
> index 40615db2..0301d739 100644
> --- a/libsepol/cil/src/cil_binary.c
> +++ b/libsepol/cil/src/cil_binary.c
> @@ -3818,6 +3818,38 @@ exit:
>         return SEPOL_ERR;
>  }
>
> +static int cil_segregateattributes_to_policydb(policydb_t *pdb, const struct cil_segregateattributes *sattrs)
> +{
> +       segregate_attributes_rule_t *sattr;
> +       struct cil_list_item *curr;
> +       type_datum_t *sepol_type;
> +       int rc = SEPOL_ERR;
> +
> +       sattr = cil_malloc(sizeof(segregate_attributes_rule_t));
> +       ebitmap_init(&sattr->attrs);
> +
> +       cil_list_for_each(curr, sattrs->datum_expr) {
> +               rc = __cil_get_sepol_type_datum(pdb, DATUM(curr->data), &sepol_type);
> +               if (rc != SEPOL_OK) goto exit;
> +
> +               if (ebitmap_set_bit(&sattr->attrs, sepol_type->s.value - 1, 1)) {
> +                       goto exit;
> +               }
> +       }
> +
> +       sattr->next = pdb->segregate_attributes;
> +       pdb->segregate_attributes = sattr;
> +
> +       return SEPOL_OK;
> +
> +exit:
> +       if (sattr) {
> +               ebitmap_destroy(&sattr->attrs);
> +               free(sattr);
> +       }
> +       return rc;
> +}
> +
>  static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args)
>  {
>         int rc = SEPOL_OK;
> @@ -3960,6 +3992,9 @@ static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args)
>                 case CIL_DEFAULTRANGE:
>                         rc = cil_defaultrange_to_policydb(pdb, node->data);
>                         break;
> +               case CIL_SEGREGATEATTRIBUTES:
> +                       rc = cil_segregateattributes_to_policydb(pdb, node->data);
> +                       break;
>                 default:
>                         break;
>                 }
> @@ -4890,6 +4925,42 @@ exit:
>         return rc;
>  }
>
> +static int cil_check_segregateattributes(const policydb_t *pdb, int *violation)
> +{
> +       const segregate_attributes_rule_t *sattr;
> +
> +       for (sattr = pdb->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_after(&sattr->attrs, second_node, second_bit, first_node, first_bit) {
> +                               ebitmap_t attr_union;
> +                               ebitmap_node_t *type_node;
> +                               unsigned int type_bit;
> +
> +                               if (ebitmap_and(&attr_union, &pdb->attr_type_map[first_bit], &pdb->attr_type_map[second_bit]))
> +                                       return SEPOL_ERR;
> +
> +                               ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) {
> +                                       cil_log(CIL_ERR, "Segregate Attributes violation, type %s associated with attributes %s and %s\n",
> +                                                        pdb->p_type_val_to_name[type_bit],
> +                                                        pdb->p_type_val_to_name[first_bit],
> +                                                        pdb->p_type_val_to_name[second_bit]);
> +                                       *violation = CIL_TRUE;

It needs to report the file and linenumber of the violation. This is
the case for checkpolicy as well. There is a reason that we carry that
information for neverallow rules.

Thanks,
Jim


> +                               }
> +
> +                               ebitmap_destroy(&attr_union);
> +                       }
> +               }
> +       }
> +
> +       return SEPOL_OK;
> +}
> +
>  static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t class, uint32_t data, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
>  {
>         struct cil_classperms *cp;
> @@ -5160,6 +5231,10 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p
>                 rc = cil_check_neverallows(db, pdb, neverallows, &violation);
>                 if (rc != SEPOL_OK) goto exit;
>
> +               cil_log(CIL_INFO, "Checking Segregate Attributes\n");
> +               rc = cil_check_segregateattributes(pdb, &violation);
> +               if (rc != SEPOL_OK) goto exit;
> +
>                 cil_log(CIL_INFO, "Checking User Bounds\n");
>                 rc = bounds_check_users(NULL, pdb);
>                 if (rc) {
> diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
> index 4177c9f6..611aade8 100644
> --- a/libsepol/cil/src/cil_build_ast.c
> +++ b/libsepol/cil/src/cil_build_ast.c
> @@ -6164,6 +6164,62 @@ void cil_destroy_src_info(struct cil_src_info *info)
>         free(info);
>  }
>
> +int cil_gen_segregateattributes(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
> +{
> +       enum cil_syntax syntax[] = {
> +               CIL_SYN_STRING,
> +               CIL_SYN_LIST,
> +               CIL_SYN_END
> +       };
> +       size_t syntax_len = sizeof(syntax)/sizeof(*syntax);
> +       struct cil_segregateattributes *sattrs = NULL;
> +       int rc = SEPOL_ERR;
> +
> +       if (db == NULL || parse_current == NULL || ast_node == NULL) {
> +               goto exit;
> +       }
> +
> +       rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       cil_segregateattributes_init(&sattrs);
> +
> +       rc = cil_gen_expr(parse_current->next, CIL_TYPEATTRIBUTE, &sattrs->str_expr);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       /* require at least two attributes */
> +       if (sattrs->str_expr->head == sattrs->str_expr->tail) {
> +               rc = SEPOL_ERR;
> +               goto exit;
> +       }
> +
> +       ast_node->data = sattrs;
> +       ast_node->flavor = CIL_SEGREGATEATTRIBUTES;
> +
> +       return SEPOL_OK;
> +
> +exit:
> +       cil_tree_log(parse_current, CIL_ERR, "Bad segregate attributes declaration");
> +       cil_destroy_segregateattributes(sattrs);
> +       return rc;
> +}
> +
> +void cil_destroy_segregateattributes(struct cil_segregateattributes *sattrs)
> +{
> +       if (sattrs == NULL) {
> +               return;
> +       }
> +
> +       cil_list_destroy(&sattrs->str_expr, CIL_TRUE);
> +       cil_list_destroy(&sattrs->datum_expr, CIL_FALSE);
> +
> +       free(sattrs);
> +}
> +
>  static int check_for_illegal_statement(struct cil_tree_node *parse_current, struct cil_args_build *args)
>  {
>         if (args->tunif != NULL) {
> @@ -6455,6 +6511,8 @@ static struct cil_tree_node * parse_statement(struct cil_db *db, struct cil_tree
>                 rc = cil_gen_mls(parse_current, new_ast_node);
>         } else if (parse_current->data == CIL_KEY_SRC_INFO) {
>                 rc = cil_gen_src_info(parse_current, new_ast_node);
> +       } else if (parse_current->data == CIL_KEY_SEGREGATEATTRIBUTES) {
> +               rc = cil_gen_segregateattributes(db, parse_current, new_ast_node);
>         } else {
>                 cil_log(CIL_ERR, "Error: Unknown keyword %s\n", (char *)parse_current->data);
>                 rc = SEPOL_ERR;
> diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h
> index fd9053ce..d815a22f 100644
> --- a/libsepol/cil/src/cil_build_ast.h
> +++ b/libsepol/cil/src/cil_build_ast.h
> @@ -225,6 +225,8 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no
>  void cil_destroy_defaultrange(struct cil_defaultrange *def);
>  int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
>  void cil_destroy_src_info(struct cil_src_info *info);
> +int cil_gen_segregateattributes(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
> +void cil_destroy_segregateattributes(struct cil_segregateattributes *sattrs);
>
>  int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats);
>  void cil_destroy_cats(struct cil_cats *cats);
> diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
> index 17f05021..e0f3ba4f 100644
> --- a/libsepol/cil/src/cil_copy_ast.c
> +++ b/libsepol/cil/src/cil_copy_ast.c
> @@ -1697,6 +1697,21 @@ static int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *da
>         return SEPOL_OK;
>  }
>
> +static int cil_copy_segregateattributes(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
> +{
> +       struct cil_segregateattributes *orig = data;
> +       struct cil_segregateattributes *new = NULL;
> +
> +       cil_segregateattributes_init(&new);
> +
> +       cil_copy_expr(db, orig->str_expr, &new->str_expr);
> +       cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
> +
> +       *copy = new;
> +
> +       return SEPOL_OK;
> +}
> +
>  static int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args)
>  {
>         int rc = SEPOL_ERR;
> @@ -1990,6 +2005,9 @@ static int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished
>         case CIL_SRC_INFO:
>                 copy_func = &cil_copy_src_info;
>                 break;
> +       case CIL_SEGREGATEATTRIBUTES:
> +               copy_func = &cil_copy_segregateattributes;
> +               break;
>         default:
>                 goto exit;
>         }
> diff --git a/libsepol/cil/src/cil_flavor.h b/libsepol/cil/src/cil_flavor.h
> index c2f0cee7..ffbd5877 100644
> --- a/libsepol/cil/src/cil_flavor.h
> +++ b/libsepol/cil/src/cil_flavor.h
> @@ -115,6 +115,7 @@ enum cil_flavor {
>         CIL_SRC_INFO,
>         CIL_IBPKEYCON,
>         CIL_IBENDPORTCON,
> +       CIL_SEGREGATEATTRIBUTES,
>
>  /*
>   *          boolean  constraint  set  catset
> diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
> index a7604762..e22c2f87 100644
> --- a/libsepol/cil/src/cil_internal.h
> +++ b/libsepol/cil/src/cil_internal.h
> @@ -242,6 +242,7 @@ extern char *CIL_KEY_SRC_CIL;
>  extern char *CIL_KEY_SRC_HLL_LMS;
>  extern char *CIL_KEY_SRC_HLL_LMX;
>  extern char *CIL_KEY_SRC_HLL_LME;
> +extern char *CIL_KEY_SEGREGATEATTRIBUTES;
>
>  /*
>         Symbol Table Array Indices
> @@ -309,6 +310,7 @@ struct cil_db {
>         struct cil_list *userprefixes;
>         struct cil_list *selinuxusers;
>         struct cil_list *names;
> +       struct cil_list *segregateattributes;
>         int num_types_and_attrs;
>         int num_classes;
>         int num_cats;
> @@ -975,6 +977,11 @@ struct cil_src_info {
>         char *path;
>  };
>
> +struct cil_segregateattributes {
> +       struct cil_list *str_expr;
> +       struct cil_list *datum_expr;
> +};
> +
>  void cil_db_init(struct cil_db **db);
>  void cil_db_destroy(struct cil_db **db);
>
> @@ -1085,5 +1092,6 @@ void cil_mls_init(struct cil_mls **mls);
>  void cil_src_info_init(struct cil_src_info **info);
>  void cil_userattribute_init(struct cil_userattribute **attribute);
>  void cil_userattributeset_init(struct cil_userattributeset **attrset);
> +void cil_segregateattributes_init(struct cil_segregateattributes **sattrs);
>
>  #endif
> diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
> index 7c543c47..36f6780d 100644
> --- a/libsepol/cil/src/cil_policy.c
> +++ b/libsepol/cil/src/cil_policy.c
> @@ -69,6 +69,7 @@ enum cil_statement_list {
>         CIL_LIST_USER,
>         CIL_LIST_CONSTRAINT,
>         CIL_LIST_VALIDATETRANS,
> +       CIL_LIST_SEGREGATEATTRIBUTES,
>         CIL_LIST_NUM_LISTS
>  };
>
> @@ -168,6 +169,9 @@ static int __cil_gather_statements_helper(struct cil_tree_node *node, uint32_t *
>         case CIL_VALIDATETRANS:
>                 kind = CIL_LIST_VALIDATETRANS;
>                 break;
> +       case CIL_SEGREGATEATTRIBUTES:
> +               kind = CIL_LIST_SEGREGATEATTRIBUTES;
> +               break;
>         default:
>                 break;
>         }
> @@ -1911,6 +1915,27 @@ static void cil_devicetreecons_to_policy(FILE *out, struct cil_sort *devicetreec
>         }
>  }
>
> +static void cil_segregateattributes_to_policy(FILE *out, struct cil_list *sattrs_list)
> +{
> +       struct cil_list_item *curr_sattrs, *curr_attr;
> +       struct cil_segregateattributes *sattrs;
> +       int first = 1;
> +
> +       cil_list_for_each(curr_sattrs, sattrs_list) {
> +               sattrs = curr_sattrs->data;
> +               fprintf(out, "segregate_attriutes ");
> +               cil_list_for_each(curr_attr, sattrs->datum_expr) {
> +                       if (!first) {
> +                               first = 0;
> +                       } else {
> +                               fprintf(out, ", ");
> +                       }
> +                       fprintf(out, "%s", DATUM(curr_attr->data)->fqn);
> +               }
> +               fprintf(out, ";\n");
> +       }
> +}
> +
>  void cil_gen_policy(FILE *out, struct cil_db *db)
>  {
>         unsigned i;
> @@ -1956,6 +1981,7 @@ void cil_gen_policy(FILE *out, struct cil_db *db)
>         cil_typebounds_to_policy(out, lists[CIL_LIST_TYPE]);
>         cil_typeattributes_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEATTRIBUTE]);
>         cil_te_rules_to_policy(out, head, db->mls);
> +       cil_segregateattributes_to_policy(out, db->segregateattributes);
>
>         cil_roles_to_policy(out, lists[CIL_LIST_ROLE]);
>         cil_role_types_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_TYPE]);
> diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c
> index 0864d7ef..c5ac83c8 100644
> --- a/libsepol/cil/src/cil_reset_ast.c
> +++ b/libsepol/cil/src/cil_reset_ast.c
> @@ -475,6 +475,11 @@ static void cil_reset_booleanif(struct cil_booleanif *bif)
>         cil_list_destroy(&bif->datum_expr, CIL_FALSE);
>  }
>
> +static void cil_reset_segregateattributes(struct cil_segregateattributes *sattrs)
> +{
> +       cil_list_destroy(&sattrs->datum_expr, CIL_FALSE);
> +}
> +
>  static int __cil_reset_node(struct cil_tree_node *node,  __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args)
>  {
>         switch (node->flavor) {
> @@ -630,6 +635,9 @@ static int __cil_reset_node(struct cil_tree_node *node,  __attribute__((unused))
>         case CIL_BOOLEANIF:
>                 cil_reset_booleanif(node->data);
>                 break;
> +       case CIL_SEGREGATEATTRIBUTES:
> +               cil_reset_segregateattributes(node->data);
> +               break;
>         case CIL_TUNABLEIF:
>         case CIL_CALL:
>                 break; /* Not effected by optional block disabling */
> diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
> index f5e22c97..36a96199 100644
> --- a/libsepol/cil/src/cil_resolve_ast.c
> +++ b/libsepol/cil/src/cil_resolve_ast.c
> @@ -3265,6 +3265,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc
>                 sym_index = CIL_SYM_TUNABLES;
>                 break;
>         case CIL_TYPE:
> +       case CIL_TYPEATTRIBUTE:
>                 sym_index = CIL_SYM_TYPES;
>                 break;
>         case CIL_ROLE:
> @@ -3312,6 +3313,13 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc
>                         } else {
>                                 if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) {
>                                         cil_type_used(res_datum, CIL_ATTR_CONSTRAINT);
> +                               } else if (expr_type == CIL_SEGREGATEATTRIBUTES) {
> +                                       if (FLAVOR(res_datum) != CIL_TYPEATTRIBUTE) {
> +                                               cil_tree_log(parent, CIL_ERR, "Type or type alias not supported in segregate attributes declaration");
> +                                               rc = SEPOL_ERR;
> +                                               goto exit;
> +                                       }
> +                                       cil_type_used(res_datum, CIL_ATTR_NEVERALLOW);
>                                 }
>                                 cil_list_append(*datum_expr, CIL_DATUM, res_datum);
>                         }
> @@ -3508,6 +3516,33 @@ exit:
>         return rc;
>  }
>
> +int cil_resolve_segregateattributes(struct cil_tree_node *current, void *extra_args)
> +{
> +       struct cil_segregateattributes *sattrs = current->data;
> +       struct cil_list_item *first, *second;
> +       int rc;
> +
> +       rc = cil_resolve_expr(CIL_SEGREGATEATTRIBUTES, sattrs->str_expr, &sattrs->datum_expr, current, extra_args);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       cil_list_for_each(first, sattrs->datum_expr) {
> +               for (second = first->next; second; second = second->next) {
> +                       if (first->data == second->data) {
> +                               cil_tree_log(current, CIL_ERR, "Repeated attribute in segregate attributes declaration");
> +                               rc = SEPOL_ERR;
> +                               goto exit;
> +                       }
> +               }
> +       }
> +
> +       return SEPOL_OK;
> +
> +exit:
> +       return rc;
> +}
> +
>  /*
>   * Degenerate inheritance leads to exponential growth of the policy
>   * It can take many forms, but here is one example.
> @@ -3888,6 +3923,9 @@ static int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
>                 case CIL_USERATTRIBUTESET:
>                         rc = cil_resolve_userattributeset(node, args);
>                         break;
> +               case CIL_SEGREGATEATTRIBUTES:
> +                       rc = cil_resolve_segregateattributes(node, args);
> +                       break;
>                 default:
>                         break;
>                 }
> diff --git a/libsepol/cil/src/cil_resolve_ast.h b/libsepol/cil/src/cil_resolve_ast.h
> index 1d971fd6..31594954 100644
> --- a/libsepol/cil/src/cil_resolve_ast.h
> +++ b/libsepol/cil/src/cil_resolve_ast.h
> @@ -96,6 +96,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc
>  int cil_resolve_boolif(struct cil_tree_node *current, void *extra_args);
>  int cil_evaluate_expr(struct cil_list *datum_expr, uint16_t *result);
>  int cil_resolve_tunif(struct cil_tree_node *current, void *extra_args);
> +int cil_resolve_segregateattributes(struct cil_tree_node *current, void *extra_args);
>
>  int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current);
>  int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_index sym_index, void *extra_args, struct cil_symtab_datum **datum);
> diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c
> index b75784ef..d0fb555b 100644
> --- a/libsepol/cil/src/cil_write_ast.c
> +++ b/libsepol/cil/src/cil_write_ast.c
> @@ -1474,7 +1474,18 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
>                 fprintf(out, "(ipaddr %s %s)\n", datum_to_str(&ipaddr->datum), buf);
>                 break;
>         }
> +       case CIL_SEGREGATEATTRIBUTES: {
> +               struct cil_segregateattributes *sattrs = node->data;
> +               fprintf(out, "(segregateattributes ");
> +               if (sattrs->datum_expr)
> +                       write_expr(out, sattrs->datum_expr);
> +               else
> +                       write_expr(out, sattrs->str_expr);
> +               fprintf(out, ")\n");
> +               break;
> +       }
>         default :
> +               cil_log(CIL_ERR, "Unsupported flavor: %d\n", node->flavor);
>                 fprintf(out, "(<?RULE:%s>)\n", cil_node_to_string(node));
>                 break;
>         }
> diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
> index 9128ac55..4b99208d 100644
> --- a/libsepol/src/kernel_to_cil.c
> +++ b/libsepol/src/kernel_to_cil.c
> @@ -1906,6 +1906,33 @@ static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
>         return 0;
>  }
>
> +static int write_segregate_attributes_to_cil(FILE *out, const struct policydb *pdb)
> +{
> +       const segregate_attributes_rule_t *sattr;
> +
> +       for (sattr = pdb->segregate_attributes; sattr; sattr = sattr->next) {
> +               struct ebitmap_node *node;
> +               unsigned int bit;
> +               int first = 1;
> +
> +               sepol_printf(out, "(segregateattributes (");
> +
> +               ebitmap_for_each_positive_bit(&sattr->attrs, node, bit) {
> +                       if (first) {
> +                               first = 0;
> +                       } else {
> +                               sepol_printf(out, " ");
> +                       }
> +
> +                       sepol_printf(out, "%s", pdb->p_type_val_to_name[bit - 1]);
> +               }
> +
> +               sepol_printf(out, "))\n");
> +       }
> +
> +       return 0;
> +}
> +
>  static int write_filename_trans_rules_to_cil(FILE *out, struct policydb *pdb)
>  {
>         struct map_filename_trans_args args;
> @@ -3329,6 +3356,11 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb)
>                 goto exit;
>         }
>
> +       rc = write_segregate_attributes_to_cil(out, pdb);
> +       if (rc != 0) {
> +               goto exit;
> +       }
> +
>         rc = write_filename_trans_rules_to_cil(out, pdb);
>         if (rc != 0) {
>                 goto exit;
> diff --git a/secilc/docs/README.md b/secilc/docs/README.md
> index efab2a71..8f584019 100644
> --- a/secilc/docs/README.md
> +++ b/secilc/docs/README.md
> @@ -132,6 +132,7 @@ CIL (Common Intermediate Language)
>    * [typemember](cil_type_statements.md#typemember)
>    * [typetransition](cil_type_statements.md#typetransition)
>    * [typepermissive](cil_type_statements.md#typepermissive)
> +  * [segregateattributes](cil_type_statements.md#segregateattributes)
>
>  * [User Statements](cil_user_statements.md#user-statements)
>    * [user](cil_user_statements.md#user)
> diff --git a/secilc/docs/cil_type_statements.md b/secilc/docs/cil_type_statements.md
> index 19438417..56533eea 100644
> --- a/secilc/docs/cil_type_statements.md
> +++ b/secilc/docs/cil_type_statements.md
> @@ -601,3 +601,53 @@ This example will allow SELinux to run the `healthd.process` domain in permissiv
>          (allow ...)
>      )
>  ```
> +
> +segregateattributes
> +-------------------
> +
> +Libsepol and secilc version 3.5 introduced the segregateattributes statement
> +to mark two or more type attributes mutual exclusive. This is a compiler
> +enforced action that will stop compilation until the offending associations
> +are modified.
> +
> +Note that these constraints can be over-ridden by the CIL compiler command
> +line parameter `-N` or `--disable-neverallow` flags.
> +
> +**Statement definition:**
> +
> +```secil
> +    (segregateattributes (typeattribute_id typeattribute_id...))
> +```
> +
> +**Where:**
> +
> +<table>
> +<colgroup>
> +<col width="27%" />
> +<col width="72%" />
> +</colgroup>
> +<tbody>
> +<tr class="odd">
> +<td align="left"><p><code>segregateattributes</code></p></td>
> +<td align="left"><p>The <code>segregateattributes</code> keyword.</p></td>
> +</tr>
> +<tr class="even">
> +<td align="left"><p><code>typeattribute_id</code></p></td>
> +<td align="left"><p>At least two previously declared <code>typeattribute</code> identifier.</p>
> +<p>Note that the same <code>typeattribute</code> identifier must not be repeated.</p></td>
> +</tr>
> +</tbody>
> +</table>
> +
> +**Example:**
> +
> +This example will not compile as `type_1` is associated with type attributes `attr_1` and `attr_2`:
> +
> +```secil
> +    (type type_1)
> +    (typeattribute attr_1)
> +    (typeattribute attr_2)
> +    (typeattributeset attr_1 (type_1))
> +    (typeattributeset attr_2 (type_1))
> +    (segregateattributes (attr_1 attr_2))
> +```
> --
> 2.36.1
>

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

* Re: [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c
  2022-08-08 15:01 ` [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c James Carter
@ 2022-08-09 15:22   ` James Carter
  0 siblings, 0 replies; 17+ messages in thread
From: James Carter @ 2022-08-09 15:22 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Mon, Aug 8, 2022 at 11:01 AM James Carter <jwcart2@gmail.com> wrote:
>
> On Thu, Jul 21, 2022 at 11:11 AM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > 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>
>
> Acked-by: James Carter <jwcart2@gmail.com>
>

I applied this patch, but none of the others from this series.
This patch really fit better with the other ebitmap work that was
being merged anyway.

Thanks,
Jim


> > ---
> >  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	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes
  2022-08-08 17:09   ` James Carter
@ 2023-08-11 16:38     ` Christian Göttsche
  2023-08-11 19:48       ` James Carter
  0 siblings, 1 reply; 17+ messages in thread
From: Christian Göttsche @ 2023-08-11 16:38 UTC (permalink / raw)
  To: James Carter; +Cc: selinux

On Mon, 8 Aug 2022 at 19:09, James Carter <jwcart2@gmail.com> wrote:
>
> On Thu, Jul 21, 2022 at 11:11 AM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > 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 | 66 +++++++++++++++++++++++++++++++++++++
> >  checkpolicy/policy_define.h |  1 +
> >  checkpolicy/policy_parse.y  |  5 +++
> >  checkpolicy/policy_scan.l   |  2 ++
> >  4 files changed, 74 insertions(+)
> >
> > diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
> > index 8bf36859..cf6fbf08 100644
> > --- a/checkpolicy/policy_define.c
> > +++ b/checkpolicy/policy_define.c
> > @@ -1220,6 +1220,72 @@ exit:
> >         return rc;
> >  }
> >
> > +int define_segregate_attributes(void)
> > +{
> > +       char *id = NULL;
> > +       segregate_attributes_rule_t *sattr = NULL;
> > +       int rc = -1;
> > +
> > +       if (pass == 1) {
> > +               while ((id = queue_remove(id_queue)))
> > +                       free(id);
> > +               return 0;
> > +       }
> > +
> > +       sattr = malloc(sizeof(segregate_attributes_rule_t));
> > +       if (!sattr) {
> > +               yyerror("Out of memory!");
> > +               goto exit;
> > +       }
> > +
> > +       ebitmap_init(&sattr->attrs);
> > +
> > +       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;
> > +               }
> > +
>
> It seems like it would be useful to check a type, so an error would be
> given if the type is associated with the attribute.
>

I am not exactly sure what you mean.
Do you like to have a policy statement like

    nevertypeattribute TYPE ATTRIBUTE;

that checks at compile time a type is not associated with an attribute?

> > +               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) {
> > +               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;}
> > +
>
> I don't see the need for comparing more than two at a time.
>
> Something like:
> disjoint_types attr1 attr2;

That would lead to quadratic growth of statements, for example in the
Reference Policy example of

    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

Also one could see supporting more than two attributes as syntactic
sugar, which the traditional language already supports, e.g.

    allow { TYPE1 TYPE2 } { TYPE3 TYPE4 } : { CLASS1 CLASS2 } perm_list;

>
> Thanks,
> Jim
>
>                        ;
> >  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	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes
  2023-08-11 16:38     ` Christian Göttsche
@ 2023-08-11 19:48       ` James Carter
  0 siblings, 0 replies; 17+ messages in thread
From: James Carter @ 2023-08-11 19:48 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: selinux

On Fri, Aug 11, 2023 at 12:38 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> On Mon, 8 Aug 2022 at 19:09, James Carter <jwcart2@gmail.com> wrote:
> >
> > On Thu, Jul 21, 2022 at 11:11 AM Christian Göttsche
> > <cgzones@googlemail.com> wrote:
> > >
> > > 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 | 66 +++++++++++++++++++++++++++++++++++++
> > >  checkpolicy/policy_define.h |  1 +
> > >  checkpolicy/policy_parse.y  |  5 +++
> > >  checkpolicy/policy_scan.l   |  2 ++
> > >  4 files changed, 74 insertions(+)
> > >
> > > diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
> > > index 8bf36859..cf6fbf08 100644
> > > --- a/checkpolicy/policy_define.c
> > > +++ b/checkpolicy/policy_define.c
> > > @@ -1220,6 +1220,72 @@ exit:
> > >         return rc;
> > >  }
> > >
> > > +int define_segregate_attributes(void)
> > > +{
> > > +       char *id = NULL;
> > > +       segregate_attributes_rule_t *sattr = NULL;
> > > +       int rc = -1;
> > > +
> > > +       if (pass == 1) {
> > > +               while ((id = queue_remove(id_queue)))
> > > +                       free(id);
> > > +               return 0;
> > > +       }
> > > +
> > > +       sattr = malloc(sizeof(segregate_attributes_rule_t));
> > > +       if (!sattr) {
> > > +               yyerror("Out of memory!");
> > > +               goto exit;
> > > +       }
> > > +
> > > +       ebitmap_init(&sattr->attrs);
> > > +
> > > +       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;
> > > +               }
> > > +
> >
> > It seems like it would be useful to check a type, so an error would be
> > given if the type is associated with the attribute.
> >
>
> I am not exactly sure what you mean.
> Do you like to have a policy statement like
>
>     nevertypeattribute TYPE ATTRIBUTE;
>
> that checks at compile time a type is not associated with an attribute?
>
> > > +               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) {
> > > +               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;}
> > > +
> >
> > I don't see the need for comparing more than two at a time.
> >
> > Something like:
> > disjoint_types attr1 attr2;
>
> That would lead to quadratic growth of statements, for example in the
> Reference Policy example of
>
>     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
>
> Also one could see supporting more than two attributes as syntactic
> sugar, which the traditional language already supports, e.g.
>
>     allow { TYPE1 TYPE2 } { TYPE3 TYPE4 } : { CLASS1 CLASS2 } perm_list;
>

The case above would be a pain to do and making it a list would be
better. I guess using a list is not that big of a deal.

The problem with checking that attributes are disjoint is that it does
not tell me *why* they should be disjoint.
It would be better to use more neverallow rules because they express
the goals of the security policy.
If a neverallow rule cannot be written to say why two attributes
should be disjoint, then either the policy is not fine-grained enough
for it to matter or there is a problem with the policy.

Jim


> >
> > Thanks,
> > Jim
> >
> >                        ;
> > >  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	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2023-08-11 19:48 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-21 15:05 [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c Christian Göttsche
2022-07-21 15:05 ` [PATCH v3 2/8] libsepol: add ebitmap iterator wrapper with startnode Christian Göttsche
2022-08-08 15:04   ` James Carter
2022-07-21 15:05 ` [PATCH v3 3/8] libsepol: add compile-time constraint for mutual exclusive attributes Christian Göttsche
2022-08-08 17:02   ` James Carter
2022-07-21 15:05 ` [PATCH v3 4/8] checkpolicy: add front-end support for segregate attributes Christian Göttsche
2022-08-08 17:09   ` James Carter
2023-08-11 16:38     ` Christian Göttsche
2023-08-11 19:48       ` James Carter
2022-07-21 15:05 ` [PATCH v3 5/8] libsepol/tests: add test " Christian Göttsche
2022-07-21 15:05 ` [PATCH v3 6/8] libsepol/cil: add support " Christian Göttsche
2022-08-08 17:15   ` James Carter
2022-07-21 15:05 ` [PATCH v3 7/8] secilc: run tests against development version of libsepol Christian Göttsche
2022-08-08 15:20   ` James Carter
2022-07-21 15:05 ` [PATCH v3 8/8] secilc: include segregate attributes in tests Christian Göttsche
2022-08-08 15:01 ` [PATCH v3 1/8] libsepol: refactor ebitmap conversion in link.c James Carter
2022-08-09 15:22   ` James Carter

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).