All of lore.kernel.org
 help / color / mirror / Atom feed
* [v2 PATCH 6/6] Support adding one role attribute into another
@ 2011-06-01  8:57 Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 1/6] Add role attribute support when compiling modules Harry Ciao
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  8:57 UTC (permalink / raw)
  To: cpebenito, sds, method, jmorris, eparis; +Cc: selinux


Hi,

This is the v2 patches to add role attribute support.

So far the only change from v1 is to introduce a new "attribute_role"
statement to declare a role attribute, rather than overloading the
"attribute" statement that aims at declaring a type attribute.

Other than that, also updated the patch header for the 6/6 patch to
support the "nesting" of role attributes, that since role_copy_callback()
would copy any symtab[SYM_ROLES] table(no matter if it's a module's global
p_roles table or from an avrule_decl_t) into base.p_roles table, it would
be enough to traverse base.p_roles table to expand sub-attribute's roles
ebitmap into that of the parent.

Thanks a lot for all your time to review these patches!

Best regards,
Harry

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* [v2 PATCH 1/6] Add role attribute support when compiling modules.
  2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
@ 2011-06-01  8:57 ` Harry Ciao
  2011-06-24 19:36   ` Steve Lawrence
  2011-06-01  8:57 ` [v2 PATCH 2/6] Add role attribute support when generating pp files Harry Ciao
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  8:57 UTC (permalink / raw)
  To: cpebenito, sds, method, jmorris, eparis; +Cc: selinux

1. Add a uint32_t "flavor" field and an ebitmap "roles" to the
role_datum_t structure;

2. Add a new "attribute_role" statement and its handler to declare
a role attribute;

3. Modify declare_role() to setup role_datum_t.flavor according
to the isattr argument;

4. Add a new "roleattribute" rule and its handler, which will record
the regular role's (policy value - 1) into the role attribute's
role_datum_t.roles ebitmap;

5. Modify the syntax for the role-types rule only to define the
role-type associations;

6. Add a new role-attr rule to support the declaration of a single
role, and optionally the role attribute that the role belongs to;

7. Check if the new_role used in role-transition rule is a regular role;

8. Support to require a role attribute;

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 checkpolicy/module_compiler.c              |   67 ++++++++++++-
 checkpolicy/module_compiler.h              |    4 +-
 checkpolicy/policy_define.c                |  152 +++++++++++++++++++++++++++-
 checkpolicy/policy_define.h                |    3 +
 checkpolicy/policy_parse.y                 |   18 +++-
 checkpolicy/policy_scan.l                  |    4 +
 libsepol/include/sepol/policydb/policydb.h |    4 +
 libsepol/src/policydb.c                    |    2 +
 8 files changed, 246 insertions(+), 8 deletions(-)

diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
index 0946ff6..1c1d1d5 100644
--- a/checkpolicy/module_compiler.c
+++ b/checkpolicy/module_compiler.c
@@ -200,7 +200,7 @@ static int role_implicit_bounds(hashtab_t roles_tab,
 	return 0;
 }
 
-role_datum_t *declare_role(void)
+role_datum_t *declare_role(unsigned char isattr)
 {
 	char *id = queue_remove(id_queue), *dest_id = NULL;
 	role_datum_t *role = NULL, *dest_role = NULL;
@@ -217,7 +217,7 @@ role_datum_t *declare_role(void)
 		return NULL;
 	}
 	role_datum_init(role);
-
+	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
 	retval =
 	    declare_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &value,
 			   &value);
@@ -254,6 +254,7 @@ role_datum_t *declare_role(void)
 			}
 			role_datum_init(dest_role);
 			dest_role->s.value = value;
+			dest_role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
 			if (role_implicit_bounds(roles_tab, dest_id, dest_role)) {
 				free(dest_id);
 				role_datum_destroy(dest_role);
@@ -548,6 +549,55 @@ type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr)
 	return dest_typdatum;
 }
 
+/* Return a role_datum_t for the local avrule_decl with the given ID.
+ * If it does not exist, create one with the same value as 'value'.
+ * This function assumes that the ID is within scope.  c.f.,
+ * is_id_in_scope().
+ *
+ * NOTE: this function usurps ownership of id afterwards.  The caller
+ * shall not reference it nor free() it afterwards.
+ */
+role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr)
+{
+	role_datum_t *dest_roledatum;
+	hashtab_t roles_tab;
+
+	assert(stack_top->type == 1);
+
+	if (stack_top->parent == NULL) {
+		/* in global, so use global symbol table */
+		roles_tab = policydbp->p_roles.table;
+	} else {
+		roles_tab = stack_top->decl->p_roles.table;
+	}
+
+	dest_roledatum = hashtab_search(roles_tab, id);
+	if (!dest_roledatum) {
+		dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t));
+		if (dest_roledatum == NULL) {
+			free(id);
+			return NULL;
+		}
+
+		role_datum_init(dest_roledatum);
+		dest_roledatum->s.value = value;
+		dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
+
+		if (hashtab_insert(roles_tab, id, dest_roledatum)) {
+			free(id);
+			role_datum_destroy(dest_roledatum);
+			free(dest_roledatum);
+			return NULL;
+		}
+	} else {
+		free(id);
+		if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE)
+			return NULL;
+	}
+	
+	return dest_roledatum;
+}
+
 /* Given the current parse stack, returns 1 if a requirement would be
  * allowed here or 0 if not.  For example, the ELSE branch may never
  * have its own requirements.
@@ -812,7 +862,7 @@ int require_class(int pass)
 	return -1;
 }
 
-int require_role(int pass)
+static int require_role_or_attribute(int pass, unsigned char isattr)
 {
 	char *id = queue_remove(id_queue);
 	role_datum_t *role = NULL;
@@ -831,6 +881,7 @@ int require_role(int pass)
 		return -1;
 	}
 	role_datum_init(role);
+	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
 	retval =
 	    require_symbol(SYM_ROLES, id, (hashtab_datum_t *) role,
 			   &role->s.value, &role->s.value);
@@ -870,6 +921,16 @@ int require_role(int pass)
 	}
 }
 
+int require_role(int pass)
+{
+	return require_role_or_attribute(pass, 0);
+}
+
+int require_attribute_role(int pass)
+{
+	return require_role_or_attribute(pass, 1);
+}
+
 static int require_type_or_attribute(int pass, unsigned char isattr)
 {
 	char *id = queue_remove(id_queue);
diff --git a/checkpolicy/module_compiler.h b/checkpolicy/module_compiler.h
index ae33753..45a21cd 100644
--- a/checkpolicy/module_compiler.h
+++ b/checkpolicy/module_compiler.h
@@ -30,11 +30,12 @@ int declare_symbol(uint32_t symbol_type,
 		   hashtab_key_t key, hashtab_datum_t datum,
 		   uint32_t * dest_value, uint32_t * datum_value);
 
-role_datum_t *declare_role(void);
+role_datum_t *declare_role(unsigned char isattr);
 type_datum_t *declare_type(unsigned char primary, unsigned char isattr);
 user_datum_t *declare_user(void);
 
 type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr);
+role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr);
 
 /* Add a symbol to the current avrule_block's require section.  Note
  * that a module may not both declare and require the same symbol.
@@ -54,6 +55,7 @@ int require_class(int pass);
 int require_role(int pass);
 int require_type(int pass);
 int require_attribute(int pass);
+int require_attribute_role(int pass);
 int require_user(int pass);
 int require_bool(int pass);
 int require_sens(int pass);
diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index f75a682..92646a0 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -1774,6 +1774,9 @@ int define_te_avtab(int which)
 	return 0;
 }
 
+/* The role-types rule is no longer used to declare regular role or
+ * role attribute, but solely aimed for declaring role-types associations.
+ */
 int define_role_types(void)
 {
 	role_datum_t *role;
@@ -1786,9 +1789,25 @@ int define_role_types(void)
 		return 0;
 	}
 
-	if ((role = declare_role()) == NULL) {
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no role name for role-types rule?");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+
+	role = hashtab_search(policydbp->p_roles.table, id);
+	if (!role) {
+		yyerror2("unknown role %s", id);
+		free(id);
 		return -1;
 	}
+
 	while ((id = queue_remove(id_queue))) {
 		if (set_types(&role->types, id, &add, 0))
 			return -1;
@@ -1797,6 +1816,132 @@ int define_role_types(void)
 	return 0;
 }
 
+int define_attrib_role(void)
+{
+	if (pass == 2) {
+		free(queue_remove(id_queue));
+		return 0;
+	}
+
+	/* Declare a role attribute */
+	if (declare_role(TRUE) == NULL)
+		return -1;
+
+	return 0;
+}
+
+int define_role_attr(void)
+{
+	char *id;
+	role_datum_t *r, *attr;
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+	
+	/* Declare a regular role */
+	if ((r = declare_role(FALSE)) == NULL)
+		return -1;
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_ROLES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_roles.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("role attribute %s is not declared", id);
+			free(id);
+			return -1;
+		}
+
+		if (attr->flavor != ROLE_ATTRIB) {
+			yyerror2("%s is a regular role, not an attribute", id);
+			free(id);
+			return -1;
+		}
+
+		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int define_roleattribute(void)
+{
+	char *id;
+	role_datum_t *r, *attr;
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no role name for roleattribute definition?");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	r = hashtab_search(policydbp->p_roles.table, id);
+	if (!r || r->flavor != ROLE_ROLE) {
+		yyerror2("unknown role %s, or not a regular role", id);
+		free(id);
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_ROLES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_roles.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("role attribute %s is not declared", id);
+			free(id);
+			return -1;
+		}
+
+		if (attr->flavor != ROLE_ATTRIB) {
+			yyerror2("%s is a regular role, not an attribute", id);
+			free(id);
+			return -1;
+		}
+
+		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2)
 {
 	role_datum_t *new;
@@ -2138,6 +2283,11 @@ int define_role_trans(int class_specified)
 		goto bad;
 	}
 
+	if (role->flavor != ROLE_ROLE) {
+		yyerror2("the new role %s must be a regular role", id);
+		goto bad;
+	}
+
 	/* This ebitmap business is just to ensure that there are not conflicting role_trans rules */
 	if (role_set_expand(&roles, &e_roles, policydbp, NULL))
 		goto bad;
diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
index 890a6af..fc8cd4d 100644
--- a/checkpolicy/policy_define.h
+++ b/checkpolicy/policy_define.h
@@ -19,6 +19,7 @@ avrule_t *define_cond_te_avtab(int which);
 avrule_t *define_cond_filename_trans(void);
 cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void* arg2);
 int define_attrib(void);
+int define_attrib_role(void);
 int define_av_perms(int inherits);
 int define_bool(void);
 int define_category(void);
@@ -48,6 +49,8 @@ int define_range_trans(int class_specified);
 int define_role_allow(void);
 int define_role_trans(int class_specified);
 int define_role_types(void);
+int define_role_attr(void);
+int define_roleattribute(void);
 int define_filename_trans(void);
 int define_sens(void);
 int define_te_avtab(int which);
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
index 8274d36..d4cc18e 100644
--- a/checkpolicy/policy_parse.y
+++ b/checkpolicy/policy_parse.y
@@ -90,6 +90,8 @@ typedef int (* require_func_t)();
 %token INHERITS
 %token SID
 %token ROLE
+%token ROLEATTRIBUTE
+%token ATTRIBUTE_ROLE
 %token ROLES
 %token TYPEALIAS
 %token TYPEATTRIBUTE
@@ -252,10 +254,13 @@ te_rbac_decl		: te_decl
 			| policycap_def
 			| ';'
                         ;
-rbac_decl		: role_type_def
+rbac_decl		: attribute_role_def
+			| role_type_def
                         | role_dominance
                         | role_trans_def
  			| role_allow_def
+			| roleattribute_def
+			| role_attr_def
 			;
 te_decl			: attribute_def
                         | type_def
@@ -415,10 +420,13 @@ dontaudit_def		: DONTAUDIT names names ':' names names ';'
 neverallow_def		: NEVERALLOW names names ':' names names  ';'
 			{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
 		        ;
+attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
+			{if (define_attrib_role()) return -1; }
 role_type_def		: ROLE identifier TYPES names ';'
 			{if (define_role_types()) return -1;}
- 			| ROLE identifier';'
- 			{if (define_role_types()) return -1;}
+			;
+role_attr_def		: ROLE identifier opt_attr_list ';'
+ 			{if (define_role_attr()) return -1;}
                         ;
 role_dominance		: DOMINANCE '{' roles '}'
 			;
@@ -440,6 +448,9 @@ role_def		: ROLE identifier_push ';'
 			| ROLE identifier_push '{' roles '}'
                         {$$ = define_role_dom((role_datum_t*)$4); if ($$ == 0) return -1;}
 			;
+roleattribute_def	: ROLEATTRIBUTE identifier id_comma_list ';'
+			{if (define_roleattribute()) return -1;}
+			;
 opt_constraints         : constraints
                         |
                         ;
@@ -804,6 +815,7 @@ require_class           : CLASS identifier names
 require_decl_def        : ROLE        { $$ = require_role; }
                         | TYPE        { $$ = require_type; }
                         | ATTRIBUTE   { $$ = require_attribute; }
+                        | ATTRIBUTE_ROLE   { $$ = require_attribute_role; }
                         | USER        { $$ = require_user; }
                         | BOOL        { $$ = require_bool; }
                         | SENSITIVITY { $$ = require_sens; }
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index 427c189..b24a087 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -76,6 +76,10 @@ ROLE |
 role				{ return(ROLE); }
 ROLES |
 roles				{ return(ROLES); }
+ROLEATTRIBUTE |
+roleattribute			{ return(ROLEATTRIBUTE);}
+ATTRIBUTE_ROLE |
+attribute_role			{ return(ATTRIBUTE_ROLE);}
 TYPES |
 types				{ return(TYPES); }
 TYPEALIAS |
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index eebf1a9..b59ab2e 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -120,6 +120,10 @@ typedef struct role_datum {
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	uint32_t bounds;	/* bounds role, if exist */
+#define ROLE_ROLE 0		/* regular role in kernel policies */
+#define ROLE_ATTRIB 1		/* attribute */
+	uint32_t flavor;
+	ebitmap_t roles;	/* roles with this attribute */
 } role_datum_t;
 
 typedef struct role_trans {
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 6d8ff91..feb35ae 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -350,6 +350,7 @@ void role_datum_init(role_datum_t * x)
 	ebitmap_init(&x->dominates);
 	type_set_init(&x->types);
 	ebitmap_init(&x->cache);
+	ebitmap_init(&x->roles);
 }
 
 void role_datum_destroy(role_datum_t * x)
@@ -358,6 +359,7 @@ void role_datum_destroy(role_datum_t * x)
 		ebitmap_destroy(&x->dominates);
 		type_set_destroy(&x->types);
 		ebitmap_destroy(&x->cache);
+		ebitmap_destroy(&x->roles);
 	}
 }
 
-- 
1.7.0.4


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* [v2 PATCH 2/6] Add role attribute support when generating pp files.
  2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 1/6] Add role attribute support when compiling modules Harry Ciao
@ 2011-06-01  8:57 ` Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 3/6] Add role attribute support when linking modules Harry Ciao
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  8:57 UTC (permalink / raw)
  To: cpebenito, sds, method, jmorris, eparis; +Cc: selinux

Add support to read/write the flavor flag and roles ebitmap in the
role_datum_t structure from/to policy module.

Note: since the role ebitmap would be expanded and won't be written
into kernel policy, kernel SELinux security server needs no change,
we don't have to introduce a new maximum version for the userspace
SELinux security server neither.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 libsepol/src/policydb.c |   11 +++++++++++
 libsepol/src/write.c    |   10 ++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index feb35ae..1e3abac 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -2071,6 +2071,17 @@ static int role_read(policydb_t * p
 		if (type_set_read(&role->types, fp))
 			goto bad;
 	}
+	
+	if (p->policy_type != POLICY_KERN) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto bad;
+
+		role->flavor = le32_to_cpu(buf[0]);
+
+		if (ebitmap_read(&role->roles, fp))
+			goto bad;
+	}
 
 	if (strcmp(key, OBJECT_R) == 0) {
 		if (role->s.value != OBJECT_R_VAL) {
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index 9657e6c..03ac7b0 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -996,6 +996,16 @@ static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
 			return POLICYDB_ERROR;
 	}
 
+	if (p->policy_type != POLICY_KERN) {
+		buf[0] = cpu_to_le32(role->flavor);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+
+		if (ebitmap_write(&role->roles, fp))
+			return POLICYDB_ERROR;
+	}
+
 	return POLICYDB_SUCCESS;
 }
 
-- 
1.7.0.4


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* [v2 PATCH 3/6] Add role attribute support when linking modules.
  2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 1/6] Add role attribute support when compiling modules Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 2/6] Add role attribute support when generating pp files Harry Ciao
@ 2011-06-01  8:57 ` Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 4/6] Add role attribute support when expanding role_datum_t Harry Ciao
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  8:57 UTC (permalink / raw)
  To: cpebenito, sds, method, jmorris, eparis; +Cc: selinux

Make the flavor flag and the roles ebitmap in role_datum_t structure
properly handled during module link process:

1. the flavor flag is copied into the base module;

2. if both the current module and the base module have defined or
required the same role, check if there is a discrepency in flavor;

3. remap the roles ebitmap and merge into its counterpart in the
base module;

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 libsepol/src/link.c |   42 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/libsepol/src/link.c b/libsepol/src/link.c
index 23dbb1b..53fcff9 100644
--- a/libsepol/src/link.c
+++ b/libsepol/src/link.c
@@ -312,7 +312,25 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 	role = (role_datum_t *) datum;
 
 	base_role = hashtab_search(state->base->p_roles.table, id);
-	if (base_role == NULL) {
+	if (base_role != NULL) {
+		/* role already exists.  check that it is what this
+		 * module expected.  duplicate declarations (e.g., two
+		 * modules both declare role foo_r) is checked during
+		 * scope_copy_callback(). */
+		if (role->flavor == ROLE_ATTRIB
+		    && base_role->flavor != ROLE_ATTRIB) {
+			ERR(state->handle,
+			    "%s: Expected %s to be a role attribute, but it was already declared as a regular role.",
+			    state->cur_mod_name, id);
+			return -1;
+		} else if (role->flavor != ROLE_ATTRIB
+			   && base_role->flavor == ROLE_ATTRIB) {
+			ERR(state->handle,
+			    "%s: Expected %s to be a regular role, but it was already declared as a role attribute.",
+			    state->cur_mod_name, id);
+			return -1;
+		}
+	} else {
 		if (state->verbose)
 			INFO(state->handle, "copying role %s", id);
 
@@ -326,8 +344,9 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 		}
 		role_datum_init(new_role);
 
-		/* new_role's dominates and types field will be copied
+		/* new_role's dominates, types and roles field will be copied
 		 * during role_fix_callback() */
+		new_role->flavor = role->flavor;
 		new_role->s.value = state->base->p_roles.nprim + 1;
 
 		ret = hashtab_insert(state->base->p_roles.table,
@@ -346,6 +365,7 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 			goto cleanup;
 		}
 		role_datum_init(new_role);
+		new_role->flavor = base_role->flavor;
 		new_role->s.value = base_role->s.value;
 		if ((new_id = strdup(id)) == NULL) {
 			goto cleanup;
@@ -1046,6 +1066,24 @@ static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
 		goto cleanup;
 	}
 	ebitmap_destroy(&e_tmp);
+	
+	if (role->flavor == ROLE_ATTRIB) {
+		ebitmap_init(&e_tmp);
+		ebitmap_for_each_bit(&role->roles, rnode, i) {
+			if (ebitmap_node_get_bit(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_union(&dest_role->roles, &e_tmp)) {
+			goto cleanup;
+		}
+		ebitmap_destroy(&e_tmp);
+	}
+
 	return 0;
 
       cleanup:
-- 
1.7.0.4


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* [v2 PATCH 4/6] Add role attribute support when expanding role_datum_t.
  2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
                   ` (2 preceding siblings ...)
  2011-06-01  8:57 ` [v2 PATCH 3/6] Add role attribute support when linking modules Harry Ciao
@ 2011-06-01  8:57 ` Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 5/6] Add role attribute support when expanding role_set_t Harry Ciao
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  8:57 UTC (permalink / raw)
  To: cpebenito, sds, method, jmorris, eparis; +Cc: selinux

1. Copy the flavor flag into its counterpart in the out module;

2. Fix all role attributes in the base module:
2.1 remap the roles ebitmap and merge into its counterpart in the
out module;
2.2 escalate the types.types ebitmap of its counterpart in the out
module, to the counterparts for all the regular roles that belongs
to the current role attribute.

The role_fix_callback() must be called after role_copy_callback()
so that state->rolemap[] is available.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 libsepol/src/expand.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index b1af365..1a94cb4 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -664,6 +664,74 @@ static int role_remap_dominates(hashtab_key_t key __attribute__ ((unused)), hash
 	return 0;
 }
 
+/* For the role attribute in the base module, escalate its counterpart's
+ * types.types ebitmap in the out module to the counterparts of all the
+ * regular role that belongs to the current role attribute. Note, must be
+ * invoked after role_copy_callback so that state->rolemap is available.
+ */
+static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+			     void *data)
+{
+	char *id, *base_reg_role_id;
+	role_datum_t *role, *new_role, *regular_role;
+	expand_state_t *state;
+	ebitmap_node_t *rnode;
+	unsigned int i;
+	ebitmap_t mapped_roles;
+
+	id = key;
+	role = (role_datum_t *)datum;
+	state = (expand_state_t *)data;
+
+	if (strcmp(id, OBJECT_R) == 0) {
+		/* object_r is never a role attribute by far */
+		return 0;
+	}
+
+	if (role->flavor != ROLE_ATTRIB)
+		return 0;
+
+	if (state->verbose)
+		INFO(state->handle, "fixing role attribute %s", id);
+
+	new_role =
+		(role_datum_t *)hashtab_search(state->out->p_roles.table, id);
+
+	assert(new_role != NULL);
+	assert(new_role->flavor == ROLE_ATTRIB);
+
+	ebitmap_init(&mapped_roles);
+	if (map_ebitmap(&role->roles, &mapped_roles, state->rolemap))
+		return -1;
+	if (ebitmap_union(&new_role->roles, &mapped_roles)) {
+		ERR(state->handle, "Out of memory!");
+		ebitmap_destroy(&mapped_roles);
+		return -1;
+	}
+	ebitmap_destroy(&mapped_roles);
+
+	ebitmap_for_each_bit(&role->roles, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			/* take advantage of sym_val_to_name[]
+			 * of the base module */
+			base_reg_role_id = state->base->p_role_val_to_name[i];
+			regular_role = (role_datum_t *)hashtab_search(
+						state->out->p_roles.table,
+						base_reg_role_id);
+			assert(regular_role != NULL);
+			assert(regular_role->flavor == ROLE_ROLE);
+
+			if (ebitmap_union(&regular_role->types.types, 
+					  &new_role->types.types)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+		}
+	}
+	
+	return 0;
+}
+
 static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 			      void *data)
 {
@@ -709,6 +777,7 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 		}
 
 		state->out->p_roles.nprim++;
+		new_role->flavor = role->flavor;
 		new_role->s.value = state->out->p_roles.nprim;
 		state->rolemap[role->s.value - 1] = new_role->s.value;
 		ret = hashtab_insert(state->out->p_roles.table,
@@ -2673,6 +2742,10 @@ int expand_module(sepol_handle_t * handle,
 	if (hashtab_map(state.base->p_roles.table,
 			role_bounds_copy_callback, &state))
 		goto cleanup;
+	/* escalate the type_set_t in a role attribute to all regular roles
+	 * that belongs to it. */
+	if (hashtab_map(state.base->p_roles.table, role_fix_callback, &state))
+		goto cleanup;
 
 	/* copy MLS's sensitivity level and categories - this needs to be done
 	 * before expanding users (they need to be indexed too) */
@@ -2725,6 +2798,9 @@ int expand_module(sepol_handle_t * handle,
 		if (hashtab_map
 		    (decl->p_roles.table, role_copy_callback, &state))
 			goto cleanup;
+		if (hashtab_map
+		    (decl->p_roles.table, role_fix_callback, &state))
+			goto cleanup;
 
 		/* copy users */
 		if (hashtab_map
-- 
1.7.0.4


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* [v2 PATCH 5/6] Add role attribute support when expanding role_set_t.
  2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
                   ` (3 preceding siblings ...)
  2011-06-01  8:57 ` [v2 PATCH 4/6] Add role attribute support when expanding role_datum_t Harry Ciao
@ 2011-06-01  8:57 ` Harry Ciao
  2011-06-01  8:57 ` [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
  2011-06-01  9:51 ` Harry Ciao
  6 siblings, 0 replies; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  8:57 UTC (permalink / raw)
  To: cpebenito, sds, method, jmorris, eparis; +Cc: selinux

When the rolemap and pointer to the base module are available, if
a non-zero bit in role_set_t.roles is a role attribute, expand it
before remap.

Note, during module compile the rolemap may not be available, the
potential duplicates of a regular role and the role attribute that
the regular role belongs to could be properly handled by
copy_role_allow() and copy_role_trans() during module expansion.

Take advantage of the role_val_to_struct[] of the base module, since
when role_set_expand() is invoked, the role_val_to_struct[] of the
out module may have not been established yet.

Also cleanup the error handling of role_set_expand().

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 checkpolicy/policy_define.c              |    2 +-
 libsepol/include/sepol/policydb/expand.h |    2 +-
 libsepol/src/expand.c                    |   57 ++++++++++++++++++++++++------
 libsepol/src/policydb.c                  |    2 +-
 libsepol/src/users.c                     |    4 +-
 5 files changed, 51 insertions(+), 16 deletions(-)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 92646a0..6faaf94 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -2289,7 +2289,7 @@ int define_role_trans(int class_specified)
 	}
 
 	/* This ebitmap business is just to ensure that there are not conflicting role_trans rules */
-	if (role_set_expand(&roles, &e_roles, policydbp, NULL))
+	if (role_set_expand(&roles, &e_roles, policydbp, NULL, NULL))
 		goto bad;
 
 	if (type_set_expand(&types, &e_types, policydbp, 1))
diff --git a/libsepol/include/sepol/policydb/expand.h b/libsepol/include/sepol/policydb/expand.h
index 059b065..31e25ec 100644
--- a/libsepol/include/sepol/policydb/expand.h
+++ b/libsepol/include/sepol/policydb/expand.h
@@ -60,7 +60,7 @@ extern int expand_convert_type_set(policydb_t * p, uint32_t * typemap,
 				   unsigned char alwaysexpand);
 extern int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p,
 			   unsigned char alwaysexpand);
-extern int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * p, uint32_t * rolemap);
+extern int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap);
 extern int mls_semantic_level_expand(mls_semantic_level_t *sl, mls_level_t *l,
                                      policydb_t *p, sepol_handle_t *h);
 extern int mls_semantic_range_expand(mls_semantic_range_t *sr, mls_range_t *r,
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index 1a94cb4..b6babb3 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -982,7 +982,7 @@ static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
 	ebitmap_init(&tmp_union);
 
 	/* get global roles for this user */
-	if (role_set_expand(&user->roles, &tmp_union, state->base, state->rolemap)) {
+	if (role_set_expand(&user->roles, &tmp_union, state->out, state->base, state->rolemap)) {
 		ERR(state->handle, "Out of memory!");
 		ebitmap_destroy(&tmp_union);
 		return -1;
@@ -1160,12 +1160,12 @@ static int copy_role_allows(expand_state_t * state, role_allow_rule_t * rules)
 		ebitmap_init(&roles);
 		ebitmap_init(&new_roles);
 
-		if (role_set_expand(&cur->roles, &roles, state->out, state->rolemap)) {
+		if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
 			ERR(state->handle, "Out of memory!");
 			return -1;
 		}
 
-		if (role_set_expand(&cur->new_roles, &new_roles, state->out, state->rolemap)) {
+		if (role_set_expand(&cur->new_roles, &new_roles, state->out, state->base, state->rolemap)) {
 			ERR(state->handle, "Out of memory!");
 			return -1;
 		}
@@ -1229,7 +1229,7 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules)
 		ebitmap_init(&roles);
 		ebitmap_init(&types);
 
-		if (role_set_expand(&cur->roles, &roles, state->out, state->rolemap)) {
+		if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
 			ERR(state->handle, "Out of memory!");
 			return -1;
 		}
@@ -2268,14 +2268,23 @@ int expand_rule(sepol_handle_t * handle,
 	return retval;
 }
 
-int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * p, uint32_t * rolemap)
+/* Expand a role set into an ebitmap containing the roles.
+ * This handles the attribute and flags.
+ * Attribute expansion depends on if the rolemap is available.
+ * During module compile the rolemap is not available, the
+ * possible duplicates of a regular role and the role attribute
+ * the regular role belongs to could be properly handled by
+ * copy_role_trans and copy_role_allow.
+ */
+int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap)
 {
 	unsigned int i;
 	ebitmap_node_t *rnode;
-	ebitmap_t mapped_roles;
+	ebitmap_t mapped_roles, roles;
+	policydb_t *p = out;
+	role_datum_t *role;
 
 	ebitmap_init(r);
-	ebitmap_init(&mapped_roles);
 
 	if (x->flags & ROLE_STAR) {
 		for (i = 0; i < p->p_roles.nprim++; i++)
@@ -2284,22 +2293,43 @@ int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * p, uint32_t * ro
 		return 0;
 	}
 
+	ebitmap_init(&mapped_roles);
+	ebitmap_init(&roles);
+	
 	if (rolemap) {
-		if (map_ebitmap(&x->roles, &mapped_roles, rolemap))
-			return -1;
+		assert(base != NULL);
+		ebitmap_for_each_bit(&x->roles, rnode, i) {
+			if (ebitmap_node_get_bit(rnode, i)) {
+				/* take advantage of p_role_val_to_struct[]
+				 * of the base module */
+				role = base->role_val_to_struct[i];
+				assert(role != NULL);
+				if (role->flavor == ROLE_ATTRIB) {
+					if (ebitmap_union(&roles,
+							  &role->roles))
+						goto bad;
+				} else {
+					if (ebitmap_set_bit(&roles, i, 1))
+						goto bad;
+				}
+			}
+		}
+		if (map_ebitmap(&roles, &mapped_roles, rolemap))
+			goto bad;
 	} else {
 		if (ebitmap_cpy(&mapped_roles, &x->roles))
-			return -1;
+			goto bad;
 	}
 
 	ebitmap_for_each_bit(&mapped_roles, rnode, i) {
 		if (ebitmap_node_get_bit(rnode, i)) {
 			if (ebitmap_set_bit(r, i, 1))
-				return -1;
+				goto bad;
 		}
 	}
 
 	ebitmap_destroy(&mapped_roles);
+	ebitmap_destroy(&roles);
 
 	/* if role is to be complimented, invert the entire bitmap here */
 	if (x->flags & ROLE_COMP) {
@@ -2314,6 +2344,11 @@ int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * p, uint32_t * ro
 		}
 	}
 	return 0;
+
+bad:
+	ebitmap_destroy(&mapped_roles);
+	ebitmap_destroy(&roles);
+	return -1;
 }
 
 /* Expand a type set into an ebitmap containing the types. This
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 1e3abac..4187f09 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -698,7 +698,7 @@ int policydb_user_cache(hashtab_key_t key
 	p = (policydb_t *) arg;
 
 	ebitmap_destroy(&user->cache);
-	if (role_set_expand(&user->roles, &user->cache, p, NULL)) {
+	if (role_set_expand(&user->roles, &user->cache, p, NULL, NULL)) {
 		return -1;
 	}
 
diff --git a/libsepol/src/users.c b/libsepol/src/users.c
index 17e1426..693210d 100644
--- a/libsepol/src/users.c
+++ b/libsepol/src/users.c
@@ -259,8 +259,8 @@ int sepol_user_modify(sepol_handle_t * handle,
 		name = NULL;
 
 		/* Expand roles */
-		if (role_set_expand
-		    (&usrdatum->roles, &usrdatum->cache, policydb, NULL)) {
+		if (role_set_expand(&usrdatum->roles, &usrdatum->cache,
+				    policydb, NULL, NULL)) {
 			ERR(handle, "unable to expand role set");
 			goto err;
 		}
-- 
1.7.0.4


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* [v2 PATCH 6/6] Support adding one role attribute into another.
  2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
                   ` (4 preceding siblings ...)
  2011-06-01  8:57 ` [v2 PATCH 5/6] Add role attribute support when expanding role_set_t Harry Ciao
@ 2011-06-01  8:57 ` Harry Ciao
  2011-06-01  9:51 ` Harry Ciao
  6 siblings, 0 replies; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  8:57 UTC (permalink / raw)
  To: cpebenito, sds, method, jmorris, eparis; +Cc: selinux

When the link process is completed, the types type_set_t and roles
ebitmap in a role attribute are settled, then we could go on to scan
all role attributes in the base.p_roles table checking if any non-zero
bit in its roles ebitmap is indeed another role attribute.

If this is the case, then we need to escalate the roles ebitmap of
the sub-attribute into that of the parent attribute, and remove the
sub-attribute from parent's roles ebitmap.

Since sub-attribute's roles ebitmap may further contain other role
attributes, we need to re-scan the updated parent's roles ebitmap.

Also if a loop dependency is detected, no escalation of sub-attribute's
roles ebitmap is needed.

Note, during the link stage, all role identifiers defined in any
block/decl of any module would not only be copied into the new block/decl
in the base module, but also copied into base.p_xxx symtabs(see
role_copy_callback), so we should only care about the hashnodes in
base.p_roles symtab and that would be enough.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 checkpolicy/policy_define.c |    5 ++-
 libsepol/src/link.c         |   62 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 6faaf94..ded27f7 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -1902,8 +1902,9 @@ int define_roleattribute(void)
 		return -1;
 	}
 	r = hashtab_search(policydbp->p_roles.table, id);
-	if (!r || r->flavor != ROLE_ROLE) {
-		yyerror2("unknown role %s, or not a regular role", id);
+	/* We support adding one role attribute into another */
+	if (!r) {
+		yyerror2("unknown role %s", id);
 		free(id);
 		return -1;
 	}
diff --git a/libsepol/src/link.c b/libsepol/src/link.c
index 53fcff9..3a6fa5a 100644
--- a/libsepol/src/link.c
+++ b/libsepol/src/link.c
@@ -2335,6 +2335,62 @@ static int prepare_base(link_state_t * state, uint32_t num_mod_decls)
 	return 0;
 }
 
+static int expand_role_attributes(hashtab_key_t key, hashtab_datum_t datum,
+				  void * data)
+{
+	char *id;
+	role_datum_t *role, *sub_attr;
+	link_state_t *state;
+	unsigned int i;
+	ebitmap_node_t *rnode;
+
+	id = key;
+	role = (role_datum_t *)datum;
+	state = (link_state_t *)data;
+
+	if (strcmp(id, OBJECT_R) == 0){
+		/* object_r is never a role attribute by far */
+		return 0;
+	}
+
+	if (role->flavor != ROLE_ATTRIB)
+		return 0;
+
+	if (state->verbose)
+		INFO(state->handle, "expanding role attribute %s", id);
+
+restart:
+	ebitmap_for_each_bit(&role->roles, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			sub_attr = state->base->role_val_to_struct[i];
+			if (sub_attr->flavor != ROLE_ATTRIB)
+				continue;
+			
+			/* remove the sub role attribute from the parent
+			 * role attribute's roles ebitmap */
+			if (ebitmap_set_bit(&role->roles, i, 0))
+				return -1;
+
+			/* loop dependency of role attributes */
+			if (sub_attr->s.value == role->s.value)
+				continue;
+
+			/* now go on to expand a sub role attribute
+			 * by escalating its roles ebitmap */
+			if (ebitmap_union(&role->roles, &sub_attr->roles)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+			
+			/* sub_attr->roles may contain other role attributes,
+			 * re-scan the parent role attribute's roles ebitmap */
+			goto restart;
+		}
+	}
+
+	return 0;
+}
+
 /* Link a set of modules into a base module. This process is somewhat
  * similar to an actual compiler: it requires a set of order dependent
  * steps.  The base and every module must have been indexed prior to
@@ -2455,6 +2511,12 @@ int link_modules(sepol_handle_t * handle,
 		goto cleanup;
 	}
 
+	/* now that all role attribute's roles ebitmap have been settled,
+	 * expand sub role attribute's roles ebitmap into that of parent */
+	if (hashtab_map
+	    (state.base->p_roles.table, expand_role_attributes, &state))
+		goto cleanup;
+
 	retval = 0;
       cleanup:
 	for (i = 0; modules != NULL && i < len; i++) {
-- 
1.7.0.4


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* Re: [v2 PATCH 6/6] Support adding one role attribute into another
  2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
                   ` (5 preceding siblings ...)
  2011-06-01  8:57 ` [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
@ 2011-06-01  9:51 ` Harry Ciao
  6 siblings, 0 replies; 10+ messages in thread
From: Harry Ciao @ 2011-06-01  9:51 UTC (permalink / raw)
  Cc: cpebenito, sds, method, jmorris, eparis, selinux

[-- Attachment #1: Type: text/plain, Size: 1161 bytes --]

Sorry, this should be the 0/6 email before all the following patches, 
the real 6/6 patch is attached.

Thanks,
Harry

On 06/01/2011 04:57 PM, Harry Ciao wrote:
>
> Hi,
>
> This is the v2 patches to add role attribute support.
>
> So far the only change from v1 is to introduce a new "attribute_role"
> statement to declare a role attribute, rather than overloading the
> "attribute" statement that aims at declaring a type attribute.
>
> Other than that, also updated the patch header for the 6/6 patch to
> support the "nesting" of role attributes, that since role_copy_callback()
> would copy any symtab[SYM_ROLES] table(no matter if it's a module's global
> p_roles table or from an avrule_decl_t) into base.p_roles table, it would
> be enough to traverse base.p_roles table to expand sub-attribute's roles
> ebitmap into that of the parent.
>
> Thanks a lot for all your time to review these patches!
>
> Best regards,
> Harry
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0006-Support-adding-one-role-attribute-into-another.patch --]
[-- Type: text/x-patch; name="0006-Support-adding-one-role-attribute-into-another.patch", Size: 0 bytes --]



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

* Re: [v2 PATCH 1/6] Add role attribute support when compiling modules.
  2011-06-01  8:57 ` [v2 PATCH 1/6] Add role attribute support when compiling modules Harry Ciao
@ 2011-06-24 19:36   ` Steve Lawrence
  2011-06-26 14:11     ` HarryCiao
  0 siblings, 1 reply; 10+ messages in thread
From: Steve Lawrence @ 2011-06-24 19:36 UTC (permalink / raw)
  To: Harry Ciao; +Cc: cpebenito, sds, method, jmorris, eparis, selinux

On 06/01/2011 04:57 AM, Harry Ciao wrote:
> 1. Add a uint32_t "flavor" field and an ebitmap "roles" to the
> role_datum_t structure;
> 
> 2. Add a new "attribute_role" statement and its handler to declare
> a role attribute;
> 
> 3. Modify declare_role() to setup role_datum_t.flavor according
> to the isattr argument;
> 
> 4. Add a new "roleattribute" rule and its handler, which will record
> the regular role's (policy value - 1) into the role attribute's
> role_datum_t.roles ebitmap;
> 
> 5. Modify the syntax for the role-types rule only to define the
> role-type associations;
> 
> 6. Add a new role-attr rule to support the declaration of a single
> role, and optionally the role attribute that the role belongs to;
> 
> 7. Check if the new_role used in role-transition rule is a regular role;
> 
> 8. Support to require a role attribute;
> 
> Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
> ---
>  checkpolicy/module_compiler.c              |   67 ++++++++++++-
>  checkpolicy/module_compiler.h              |    4 +-
>  checkpolicy/policy_define.c                |  152 +++++++++++++++++++++++++++-
>  checkpolicy/policy_define.h                |    3 +
>  checkpolicy/policy_parse.y                 |   18 +++-
>  checkpolicy/policy_scan.l                  |    4 +
>  libsepol/include/sepol/policydb/policydb.h |    4 +
>  libsepol/src/policydb.c                    |    2 +
>  8 files changed, 246 insertions(+), 8 deletions(-)
> 
> diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
> index 0946ff6..1c1d1d5 100644
> --- a/checkpolicy/module_compiler.c
> +++ b/checkpolicy/module_compiler.c
> @@ -200,7 +200,7 @@ static int role_implicit_bounds(hashtab_t roles_tab,
>  	return 0;
>  }
>  
> -role_datum_t *declare_role(void)
> +role_datum_t *declare_role(unsigned char isattr)

I'm still looking at this patchset, but noticed some issue with this
function:

The declare_role function allows a role to be defined multiple times,
which is correct. However, if a role_attribute was defined with the same
name as a role, this function would not error, which I believe it should.

Also, attribute_role's should not be allowed to be defined twice (the
same restriction is applied to normal attributes).

>  {
>  	char *id = queue_remove(id_queue), *dest_id = NULL;
>  	role_datum_t *role = NULL, *dest_role = NULL;
> @@ -217,7 +217,7 @@ role_datum_t *declare_role(void)
>  		return NULL;
>  	}
>  	role_datum_init(role);
> -
> +	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
>  	retval =
>  	    declare_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &value,
>  			   &value);
> @@ -254,6 +254,7 @@ role_datum_t *declare_role(void)
>  			}
>  			role_datum_init(dest_role);
>  			dest_role->s.value = value;
> +			dest_role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
>  			if (role_implicit_bounds(roles_tab, dest_id, dest_role)) {
>  				free(dest_id);
>  				role_datum_destroy(dest_role);
> @@ -548,6 +549,55 @@ type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr)
>  	return dest_typdatum;
>  }
>  
> +/* Return a role_datum_t for the local avrule_decl with the given ID.
> + * If it does not exist, create one with the same value as 'value'.
> + * This function assumes that the ID is within scope.  c.f.,
> + * is_id_in_scope().
> + *
> + * NOTE: this function usurps ownership of id afterwards.  The caller
> + * shall not reference it nor free() it afterwards.
> + */
> +role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr)
> +{
> +	role_datum_t *dest_roledatum;
> +	hashtab_t roles_tab;
> +
> +	assert(stack_top->type == 1);
> +
> +	if (stack_top->parent == NULL) {
> +		/* in global, so use global symbol table */
> +		roles_tab = policydbp->p_roles.table;
> +	} else {
> +		roles_tab = stack_top->decl->p_roles.table;
> +	}
> +
> +	dest_roledatum = hashtab_search(roles_tab, id);
> +	if (!dest_roledatum) {
> +		dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t));
> +		if (dest_roledatum == NULL) {
> +			free(id);
> +			return NULL;
> +		}
> +
> +		role_datum_init(dest_roledatum);
> +		dest_roledatum->s.value = value;
> +		dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
> +
> +		if (hashtab_insert(roles_tab, id, dest_roledatum)) {
> +			free(id);
> +			role_datum_destroy(dest_roledatum);
> +			free(dest_roledatum);
> +			return NULL;
> +		}
> +	} else {
> +		free(id);
> +		if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE)
> +			return NULL;
> +	}
> +	
> +	return dest_roledatum;
> +}
> +
>  /* Given the current parse stack, returns 1 if a requirement would be
>   * allowed here or 0 if not.  For example, the ELSE branch may never
>   * have its own requirements.
> @@ -812,7 +862,7 @@ int require_class(int pass)
>  	return -1;
>  }
>  
> -int require_role(int pass)
> +static int require_role_or_attribute(int pass, unsigned char isattr)
>  {
>  	char *id = queue_remove(id_queue);
>  	role_datum_t *role = NULL;
> @@ -831,6 +881,7 @@ int require_role(int pass)
>  		return -1;
>  	}
>  	role_datum_init(role);
> +	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
>  	retval =
>  	    require_symbol(SYM_ROLES, id, (hashtab_datum_t *) role,
>  			   &role->s.value, &role->s.value);
> @@ -870,6 +921,16 @@ int require_role(int pass)
>  	}
>  }
>  
> +int require_role(int pass)
> +{
> +	return require_role_or_attribute(pass, 0);
> +}
> +
> +int require_attribute_role(int pass)
> +{
> +	return require_role_or_attribute(pass, 1);
> +}
> +
>  static int require_type_or_attribute(int pass, unsigned char isattr)
>  {
>  	char *id = queue_remove(id_queue);
> diff --git a/checkpolicy/module_compiler.h b/checkpolicy/module_compiler.h
> index ae33753..45a21cd 100644
> --- a/checkpolicy/module_compiler.h
> +++ b/checkpolicy/module_compiler.h
> @@ -30,11 +30,12 @@ int declare_symbol(uint32_t symbol_type,
>  		   hashtab_key_t key, hashtab_datum_t datum,
>  		   uint32_t * dest_value, uint32_t * datum_value);
>  
> -role_datum_t *declare_role(void);
> +role_datum_t *declare_role(unsigned char isattr);
>  type_datum_t *declare_type(unsigned char primary, unsigned char isattr);
>  user_datum_t *declare_user(void);
>  
>  type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr);
> +role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr);
>  
>  /* Add a symbol to the current avrule_block's require section.  Note
>   * that a module may not both declare and require the same symbol.
> @@ -54,6 +55,7 @@ int require_class(int pass);
>  int require_role(int pass);
>  int require_type(int pass);
>  int require_attribute(int pass);
> +int require_attribute_role(int pass);
>  int require_user(int pass);
>  int require_bool(int pass);
>  int require_sens(int pass);
> diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
> index f75a682..92646a0 100644
> --- a/checkpolicy/policy_define.c
> +++ b/checkpolicy/policy_define.c
> @@ -1774,6 +1774,9 @@ int define_te_avtab(int which)
>  	return 0;
>  }
>  
> +/* The role-types rule is no longer used to declare regular role or
> + * role attribute, but solely aimed for declaring role-types associations.
> + */
>  int define_role_types(void)
>  {
>  	role_datum_t *role;
> @@ -1786,9 +1789,25 @@ int define_role_types(void)
>  		return 0;
>  	}
>  
> -	if ((role = declare_role()) == NULL) {
> +	id = (char *)queue_remove(id_queue);
> +	if (!id) {
> +		yyerror("no role name for role-types rule?");
> +		return -1;
> +	}
> +
> +	if (!is_id_in_scope(SYM_ROLES, id)) {
> +		yyerror2("role %s is not within scope", id);
> +		free(id);
> +		return -1;
> +	}
> +
> +	role = hashtab_search(policydbp->p_roles.table, id);
> +	if (!role) {
> +		yyerror2("unknown role %s", id);
> +		free(id);
>  		return -1;
>  	}
> +
>  	while ((id = queue_remove(id_queue))) {
>  		if (set_types(&role->types, id, &add, 0))
>  			return -1;
> @@ -1797,6 +1816,132 @@ int define_role_types(void)
>  	return 0;
>  }
>  
> +int define_attrib_role(void)
> +{
> +	if (pass == 2) {
> +		free(queue_remove(id_queue));
> +		return 0;
> +	}
> +
> +	/* Declare a role attribute */
> +	if (declare_role(TRUE) == NULL)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +int define_role_attr(void)
> +{
> +	char *id;
> +	role_datum_t *r, *attr;
> +
> +	if (pass == 2) {
> +		while ((id = queue_remove(id_queue)))
> +			free(id);
> +		return 0;
> +	}
> +	
> +	/* Declare a regular role */
> +	if ((r = declare_role(FALSE)) == NULL)
> +		return -1;
> +
> +	while ((id = queue_remove(id_queue))) {
> +		if (!is_id_in_scope(SYM_ROLES, id)) {
> +			yyerror2("attribute %s is not within scope", id);
> +			free(id);
> +			return -1;
> +		}
> +		attr = hashtab_search(policydbp->p_roles.table, id);
> +		if (!attr) {
> +			/* treat it as a fatal error */
> +			yyerror2("role attribute %s is not declared", id);
> +			free(id);
> +			return -1;
> +		}
> +
> +		if (attr->flavor != ROLE_ATTRIB) {
> +			yyerror2("%s is a regular role, not an attribute", id);
> +			free(id);
> +			return -1;
> +		}
> +
> +		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
> +			yyerror("Out of memory!");
> +			return -1;
> +		}
> +
> +		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
> +			yyerror("out of memory");
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int define_roleattribute(void)
> +{
> +	char *id;
> +	role_datum_t *r, *attr;
> +
> +	if (pass == 2) {
> +		while ((id = queue_remove(id_queue)))
> +			free(id);
> +		return 0;
> +	}
> +
> +	id = (char *)queue_remove(id_queue);
> +	if (!id) {
> +		yyerror("no role name for roleattribute definition?");
> +		return -1;
> +	}
> +
> +	if (!is_id_in_scope(SYM_ROLES, id)) {
> +		yyerror2("role %s is not within scope", id);
> +		free(id);
> +		return -1;
> +	}
> +	r = hashtab_search(policydbp->p_roles.table, id);
> +	if (!r || r->flavor != ROLE_ROLE) {
> +		yyerror2("unknown role %s, or not a regular role", id);
> +		free(id);
> +		return -1;
> +	}
> +
> +	while ((id = queue_remove(id_queue))) {
> +		if (!is_id_in_scope(SYM_ROLES, id)) {
> +			yyerror2("attribute %s is not within scope", id);
> +			free(id);
> +			return -1;
> +		}
> +		attr = hashtab_search(policydbp->p_roles.table, id);
> +		if (!attr) {
> +			/* treat it as a fatal error */
> +			yyerror2("role attribute %s is not declared", id);
> +			free(id);
> +			return -1;
> +		}
> +
> +		if (attr->flavor != ROLE_ATTRIB) {
> +			yyerror2("%s is a regular role, not an attribute", id);
> +			free(id);
> +			return -1;
> +		}
> +
> +		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
> +			yyerror("Out of memory!");
> +			return -1;
> +		}
> +
> +		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
> +			yyerror("out of memory");
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2)
>  {
>  	role_datum_t *new;
> @@ -2138,6 +2283,11 @@ int define_role_trans(int class_specified)
>  		goto bad;
>  	}
>  
> +	if (role->flavor != ROLE_ROLE) {
> +		yyerror2("the new role %s must be a regular role", id);
> +		goto bad;
> +	}
> +
>  	/* This ebitmap business is just to ensure that there are not conflicting role_trans rules */
>  	if (role_set_expand(&roles, &e_roles, policydbp, NULL))
>  		goto bad;
> diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
> index 890a6af..fc8cd4d 100644
> --- a/checkpolicy/policy_define.h
> +++ b/checkpolicy/policy_define.h
> @@ -19,6 +19,7 @@ avrule_t *define_cond_te_avtab(int which);
>  avrule_t *define_cond_filename_trans(void);
>  cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void* arg2);
>  int define_attrib(void);
> +int define_attrib_role(void);
>  int define_av_perms(int inherits);
>  int define_bool(void);
>  int define_category(void);
> @@ -48,6 +49,8 @@ int define_range_trans(int class_specified);
>  int define_role_allow(void);
>  int define_role_trans(int class_specified);
>  int define_role_types(void);
> +int define_role_attr(void);
> +int define_roleattribute(void);
>  int define_filename_trans(void);
>  int define_sens(void);
>  int define_te_avtab(int which);
> diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
> index 8274d36..d4cc18e 100644
> --- a/checkpolicy/policy_parse.y
> +++ b/checkpolicy/policy_parse.y
> @@ -90,6 +90,8 @@ typedef int (* require_func_t)();
>  %token INHERITS
>  %token SID
>  %token ROLE
> +%token ROLEATTRIBUTE
> +%token ATTRIBUTE_ROLE
>  %token ROLES
>  %token TYPEALIAS
>  %token TYPEATTRIBUTE
> @@ -252,10 +254,13 @@ te_rbac_decl		: te_decl
>  			| policycap_def
>  			| ';'
>                          ;
> -rbac_decl		: role_type_def
> +rbac_decl		: attribute_role_def
> +			| role_type_def
>                          | role_dominance
>                          | role_trans_def
>   			| role_allow_def
> +			| roleattribute_def
> +			| role_attr_def
>  			;
>  te_decl			: attribute_def
>                          | type_def
> @@ -415,10 +420,13 @@ dontaudit_def		: DONTAUDIT names names ':' names names ';'
>  neverallow_def		: NEVERALLOW names names ':' names names  ';'
>  			{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
>  		        ;
> +attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
> +			{if (define_attrib_role()) return -1; }
>  role_type_def		: ROLE identifier TYPES names ';'
>  			{if (define_role_types()) return -1;}
> - 			| ROLE identifier';'
> - 			{if (define_role_types()) return -1;}
> +			;
> +role_attr_def		: ROLE identifier opt_attr_list ';'
> + 			{if (define_role_attr()) return -1;}
>                          ;
>  role_dominance		: DOMINANCE '{' roles '}'
>  			;
> @@ -440,6 +448,9 @@ role_def		: ROLE identifier_push ';'
>  			| ROLE identifier_push '{' roles '}'
>                          {$$ = define_role_dom((role_datum_t*)$4); if ($$ == 0) return -1;}
>  			;
> +roleattribute_def	: ROLEATTRIBUTE identifier id_comma_list ';'
> +			{if (define_roleattribute()) return -1;}
> +			;
>  opt_constraints         : constraints
>                          |
>                          ;
> @@ -804,6 +815,7 @@ require_class           : CLASS identifier names
>  require_decl_def        : ROLE        { $$ = require_role; }
>                          | TYPE        { $$ = require_type; }
>                          | ATTRIBUTE   { $$ = require_attribute; }
> +                        | ATTRIBUTE_ROLE   { $$ = require_attribute_role; }
>                          | USER        { $$ = require_user; }
>                          | BOOL        { $$ = require_bool; }
>                          | SENSITIVITY { $$ = require_sens; }
> diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
> index 427c189..b24a087 100644
> --- a/checkpolicy/policy_scan.l
> +++ b/checkpolicy/policy_scan.l
> @@ -76,6 +76,10 @@ ROLE |
>  role				{ return(ROLE); }
>  ROLES |
>  roles				{ return(ROLES); }
> +ROLEATTRIBUTE |
> +roleattribute			{ return(ROLEATTRIBUTE);}
> +ATTRIBUTE_ROLE |
> +attribute_role			{ return(ATTRIBUTE_ROLE);}
>  TYPES |
>  types				{ return(TYPES); }
>  TYPEALIAS |
> diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
> index eebf1a9..b59ab2e 100644
> --- a/libsepol/include/sepol/policydb/policydb.h
> +++ b/libsepol/include/sepol/policydb/policydb.h
> @@ -120,6 +120,10 @@ typedef struct role_datum {
>  	type_set_t types;	/* set of authorized types for role */
>  	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
>  	uint32_t bounds;	/* bounds role, if exist */
> +#define ROLE_ROLE 0		/* regular role in kernel policies */
> +#define ROLE_ATTRIB 1		/* attribute */
> +	uint32_t flavor;
> +	ebitmap_t roles;	/* roles with this attribute */
>  } role_datum_t;
>  
>  typedef struct role_trans {
> diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> index 6d8ff91..feb35ae 100644
> --- a/libsepol/src/policydb.c
> +++ b/libsepol/src/policydb.c
> @@ -350,6 +350,7 @@ void role_datum_init(role_datum_t * x)
>  	ebitmap_init(&x->dominates);
>  	type_set_init(&x->types);
>  	ebitmap_init(&x->cache);
> +	ebitmap_init(&x->roles);
>  }
>  
>  void role_datum_destroy(role_datum_t * x)
> @@ -358,6 +359,7 @@ void role_datum_destroy(role_datum_t * x)
>  		ebitmap_destroy(&x->dominates);
>  		type_set_destroy(&x->types);
>  		ebitmap_destroy(&x->cache);
> +		ebitmap_destroy(&x->roles);
>  	}
>  }
>  


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

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

* RE: [v2 PATCH 1/6] Add role attribute support when compiling modules.
  2011-06-24 19:36   ` Steve Lawrence
@ 2011-06-26 14:11     ` HarryCiao
  0 siblings, 0 replies; 10+ messages in thread
From: HarryCiao @ 2011-06-26 14:11 UTC (permalink / raw)
  To: lawrence steve
  Cc: Christopher J. PeBenito, Stephen Smalley, method, jmorris,
	eparis, selinux-mailing-list


[-- Attachment #1.1: Type: text/plain, Size: 18612 bytes --]


Hi Steve,

> Date: Fri, 24 Jun 2011 15:36:28 -0400
> From: slawrence@tresys.com
> To: qingtao.cao@windriver.com
> CC: cpebenito@tresys.com; sds@tycho.nsa.gov; method@manicmethod.com; jmorris@namei.org; eparis@parisplace.org; selinux@tycho.nsa.gov
> Subject: Re: [v2 PATCH 1/6] Add role attribute support when compiling modules.
> 
> On 06/01/2011 04:57 AM, Harry Ciao wrote:
> > 1. Add a uint32_t "flavor" field and an ebitmap "roles" to the
> > role_datum_t structure;
> > 
> > 2. Add a new "attribute_role" statement and its handler to declare
> > a role attribute;
> > 
> > 3. Modify declare_role() to setup role_datum_t.flavor according
> > to the isattr argument;
> > 
> > 4. Add a new "roleattribute" rule and its handler, which will record
> > the regular role's (policy value - 1) into the role attribute's
> > role_datum_t.roles ebitmap;
> > 
> > 5. Modify the syntax for the role-types rule only to define the
> > role-type associations;
> > 
> > 6. Add a new role-attr rule to support the declaration of a single
> > role, and optionally the role attribute that the role belongs to;
> > 
> > 7. Check if the new_role used in role-transition rule is a regular role;
> > 
> > 8. Support to require a role attribute;
> > 
> > Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
> > ---
> >  checkpolicy/module_compiler.c              |   67 ++++++++++++-
> >  checkpolicy/module_compiler.h              |    4 +-
> >  checkpolicy/policy_define.c                |  152 +++++++++++++++++++++++++++-
> >  checkpolicy/policy_define.h                |    3 +
> >  checkpolicy/policy_parse.y                 |   18 +++-
> >  checkpolicy/policy_scan.l                  |    4 +
> >  libsepol/include/sepol/policydb/policydb.h |    4 +
> >  libsepol/src/policydb.c                    |    2 +
> >  8 files changed, 246 insertions(+), 8 deletions(-)
> > 
> > diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
> > index 0946ff6..1c1d1d5 100644
> > --- a/checkpolicy/module_compiler.c
> > +++ b/checkpolicy/module_compiler.c
> > @@ -200,7 +200,7 @@ static int role_implicit_bounds(hashtab_t roles_tab,
> >  	return 0;
> >  }
> >  
> > -role_datum_t *declare_role(void)
> > +role_datum_t *declare_role(unsigned char isattr)
> 
> I'm still looking at this patchset, but noticed some issue with this
> function:
> 
> The declare_role function allows a role to be defined multiple times,
> which is correct. However, if a role_attribute was defined with the same
> name as a role, this function would not error, which I believe it should.
> 
> Also, attribute_role's should not be allowed to be defined twice (the
> same restriction is applied to normal attributes).


Right, I've got your point, so far the role_copy_callback() function in the link stage could catch the error that a same name is defined twice in two different modules: once as a role attribute but then as a regular role. However, if such error is within a single module, or one role attribute is declared more than once in one single module, these errors can't be caught in the compile time.

Fortunately,  these errors could be detected by the symtab_insert() function, please refer to the attached v3 version for the 0001 patch, while the rest patches in the patchset remain the same so far.

Thanks!

Best regards,
Harry


> 
> >  {
> >  	char *id = queue_remove(id_queue), *dest_id = NULL;
> >  	role_datum_t *role = NULL, *dest_role = NULL;
> > @@ -217,7 +217,7 @@ role_datum_t *declare_role(void)
> >  		return NULL;
> >  	}
> >  	role_datum_init(role);
> > -
> > +	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
> >  	retval =
> >  	    declare_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &value,
> >  			   &value);
> > @@ -254,6 +254,7 @@ role_datum_t *declare_role(void)
> >  			}
> >  			role_datum_init(dest_role);
> >  			dest_role->s.value = value;
> > +			dest_role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
> >  			if (role_implicit_bounds(roles_tab, dest_id, dest_role)) {
> >  				free(dest_id);
> >  				role_datum_destroy(dest_role);
> > @@ -548,6 +549,55 @@ type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr)
> >  	return dest_typdatum;
> >  }
> >  
> > +/* Return a role_datum_t for the local avrule_decl with the given ID.
> > + * If it does not exist, create one with the same value as 'value'.
> > + * This function assumes that the ID is within scope.  c.f.,
> > + * is_id_in_scope().
> > + *
> > + * NOTE: this function usurps ownership of id afterwards.  The caller
> > + * shall not reference it nor free() it afterwards.
> > + */
> > +role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr)
> > +{
> > +	role_datum_t *dest_roledatum;
> > +	hashtab_t roles_tab;
> > +
> > +	assert(stack_top->type == 1);
> > +
> > +	if (stack_top->parent == NULL) {
> > +		/* in global, so use global symbol table */
> > +		roles_tab = policydbp->p_roles.table;
> > +	} else {
> > +		roles_tab = stack_top->decl->p_roles.table;
> > +	}
> > +
> > +	dest_roledatum = hashtab_search(roles_tab, id);
> > +	if (!dest_roledatum) {
> > +		dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t));
> > +		if (dest_roledatum == NULL) {
> > +			free(id);
> > +			return NULL;
> > +		}
> > +
> > +		role_datum_init(dest_roledatum);
> > +		dest_roledatum->s.value = value;
> > +		dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
> > +
> > +		if (hashtab_insert(roles_tab, id, dest_roledatum)) {
> > +			free(id);
> > +			role_datum_destroy(dest_roledatum);
> > +			free(dest_roledatum);
> > +			return NULL;
> > +		}
> > +	} else {
> > +		free(id);
> > +		if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE)
> > +			return NULL;
> > +	}
> > +	
> > +	return dest_roledatum;
> > +}
> > +
> >  /* Given the current parse stack, returns 1 if a requirement would be
> >   * allowed here or 0 if not.  For example, the ELSE branch may never
> >   * have its own requirements.
> > @@ -812,7 +862,7 @@ int require_class(int pass)
> >  	return -1;
> >  }
> >  
> > -int require_role(int pass)
> > +static int require_role_or_attribute(int pass, unsigned char isattr)
> >  {
> >  	char *id = queue_remove(id_queue);
> >  	role_datum_t *role = NULL;
> > @@ -831,6 +881,7 @@ int require_role(int pass)
> >  		return -1;
> >  	}
> >  	role_datum_init(role);
> > +	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
> >  	retval =
> >  	    require_symbol(SYM_ROLES, id, (hashtab_datum_t *) role,
> >  			   &role->s.value, &role->s.value);
> > @@ -870,6 +921,16 @@ int require_role(int pass)
> >  	}
> >  }
> >  
> > +int require_role(int pass)
> > +{
> > +	return require_role_or_attribute(pass, 0);
> > +}
> > +
> > +int require_attribute_role(int pass)
> > +{
> > +	return require_role_or_attribute(pass, 1);
> > +}
> > +
> >  static int require_type_or_attribute(int pass, unsigned char isattr)
> >  {
> >  	char *id = queue_remove(id_queue);
> > diff --git a/checkpolicy/module_compiler.h b/checkpolicy/module_compiler.h
> > index ae33753..45a21cd 100644
> > --- a/checkpolicy/module_compiler.h
> > +++ b/checkpolicy/module_compiler.h
> > @@ -30,11 +30,12 @@ int declare_symbol(uint32_t symbol_type,
> >  		   hashtab_key_t key, hashtab_datum_t datum,
> >  		   uint32_t * dest_value, uint32_t * datum_value);
> >  
> > -role_datum_t *declare_role(void);
> > +role_datum_t *declare_role(unsigned char isattr);
> >  type_datum_t *declare_type(unsigned char primary, unsigned char isattr);
> >  user_datum_t *declare_user(void);
> >  
> >  type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr);
> > +role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr);
> >  
> >  /* Add a symbol to the current avrule_block's require section.  Note
> >   * that a module may not both declare and require the same symbol.
> > @@ -54,6 +55,7 @@ int require_class(int pass);
> >  int require_role(int pass);
> >  int require_type(int pass);
> >  int require_attribute(int pass);
> > +int require_attribute_role(int pass);
> >  int require_user(int pass);
> >  int require_bool(int pass);
> >  int require_sens(int pass);
> > diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
> > index f75a682..92646a0 100644
> > --- a/checkpolicy/policy_define.c
> > +++ b/checkpolicy/policy_define.c
> > @@ -1774,6 +1774,9 @@ int define_te_avtab(int which)
> >  	return 0;
> >  }
> >  
> > +/* The role-types rule is no longer used to declare regular role or
> > + * role attribute, but solely aimed for declaring role-types associations.
> > + */
> >  int define_role_types(void)
> >  {
> >  	role_datum_t *role;
> > @@ -1786,9 +1789,25 @@ int define_role_types(void)
> >  		return 0;
> >  	}
> >  
> > -	if ((role = declare_role()) == NULL) {
> > +	id = (char *)queue_remove(id_queue);
> > +	if (!id) {
> > +		yyerror("no role name for role-types rule?");
> > +		return -1;
> > +	}
> > +
> > +	if (!is_id_in_scope(SYM_ROLES, id)) {
> > +		yyerror2("role %s is not within scope", id);
> > +		free(id);
> > +		return -1;
> > +	}
> > +
> > +	role = hashtab_search(policydbp->p_roles.table, id);
> > +	if (!role) {
> > +		yyerror2("unknown role %s", id);
> > +		free(id);
> >  		return -1;
> >  	}
> > +
> >  	while ((id = queue_remove(id_queue))) {
> >  		if (set_types(&role->types, id, &add, 0))
> >  			return -1;
> > @@ -1797,6 +1816,132 @@ int define_role_types(void)
> >  	return 0;
> >  }
> >  
> > +int define_attrib_role(void)
> > +{
> > +	if (pass == 2) {
> > +		free(queue_remove(id_queue));
> > +		return 0;
> > +	}
> > +
> > +	/* Declare a role attribute */
> > +	if (declare_role(TRUE) == NULL)
> > +		return -1;
> > +
> > +	return 0;
> > +}
> > +
> > +int define_role_attr(void)
> > +{
> > +	char *id;
> > +	role_datum_t *r, *attr;
> > +
> > +	if (pass == 2) {
> > +		while ((id = queue_remove(id_queue)))
> > +			free(id);
> > +		return 0;
> > +	}
> > +	
> > +	/* Declare a regular role */
> > +	if ((r = declare_role(FALSE)) == NULL)
> > +		return -1;
> > +
> > +	while ((id = queue_remove(id_queue))) {
> > +		if (!is_id_in_scope(SYM_ROLES, id)) {
> > +			yyerror2("attribute %s is not within scope", id);
> > +			free(id);
> > +			return -1;
> > +		}
> > +		attr = hashtab_search(policydbp->p_roles.table, id);
> > +		if (!attr) {
> > +			/* treat it as a fatal error */
> > +			yyerror2("role attribute %s is not declared", id);
> > +			free(id);
> > +			return -1;
> > +		}
> > +
> > +		if (attr->flavor != ROLE_ATTRIB) {
> > +			yyerror2("%s is a regular role, not an attribute", id);
> > +			free(id);
> > +			return -1;
> > +		}
> > +
> > +		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
> > +			yyerror("Out of memory!");
> > +			return -1;
> > +		}
> > +
> > +		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
> > +			yyerror("out of memory");
> > +			return -1;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int define_roleattribute(void)
> > +{
> > +	char *id;
> > +	role_datum_t *r, *attr;
> > +
> > +	if (pass == 2) {
> > +		while ((id = queue_remove(id_queue)))
> > +			free(id);
> > +		return 0;
> > +	}
> > +
> > +	id = (char *)queue_remove(id_queue);
> > +	if (!id) {
> > +		yyerror("no role name for roleattribute definition?");
> > +		return -1;
> > +	}
> > +
> > +	if (!is_id_in_scope(SYM_ROLES, id)) {
> > +		yyerror2("role %s is not within scope", id);
> > +		free(id);
> > +		return -1;
> > +	}
> > +	r = hashtab_search(policydbp->p_roles.table, id);
> > +	if (!r || r->flavor != ROLE_ROLE) {
> > +		yyerror2("unknown role %s, or not a regular role", id);
> > +		free(id);
> > +		return -1;
> > +	}
> > +
> > +	while ((id = queue_remove(id_queue))) {
> > +		if (!is_id_in_scope(SYM_ROLES, id)) {
> > +			yyerror2("attribute %s is not within scope", id);
> > +			free(id);
> > +			return -1;
> > +		}
> > +		attr = hashtab_search(policydbp->p_roles.table, id);
> > +		if (!attr) {
> > +			/* treat it as a fatal error */
> > +			yyerror2("role attribute %s is not declared", id);
> > +			free(id);
> > +			return -1;
> > +		}
> > +
> > +		if (attr->flavor != ROLE_ATTRIB) {
> > +			yyerror2("%s is a regular role, not an attribute", id);
> > +			free(id);
> > +			return -1;
> > +		}
> > +
> > +		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
> > +			yyerror("Out of memory!");
> > +			return -1;
> > +		}
> > +
> > +		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
> > +			yyerror("out of memory");
> > +			return -1;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2)
> >  {
> >  	role_datum_t *new;
> > @@ -2138,6 +2283,11 @@ int define_role_trans(int class_specified)
> >  		goto bad;
> >  	}
> >  
> > +	if (role->flavor != ROLE_ROLE) {
> > +		yyerror2("the new role %s must be a regular role", id);
> > +		goto bad;
> > +	}
> > +
> >  	/* This ebitmap business is just to ensure that there are not conflicting role_trans rules */
> >  	if (role_set_expand(&roles, &e_roles, policydbp, NULL))
> >  		goto bad;
> > diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
> > index 890a6af..fc8cd4d 100644
> > --- a/checkpolicy/policy_define.h
> > +++ b/checkpolicy/policy_define.h
> > @@ -19,6 +19,7 @@ avrule_t *define_cond_te_avtab(int which);
> >  avrule_t *define_cond_filename_trans(void);
> >  cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void* arg2);
> >  int define_attrib(void);
> > +int define_attrib_role(void);
> >  int define_av_perms(int inherits);
> >  int define_bool(void);
> >  int define_category(void);
> > @@ -48,6 +49,8 @@ int define_range_trans(int class_specified);
> >  int define_role_allow(void);
> >  int define_role_trans(int class_specified);
> >  int define_role_types(void);
> > +int define_role_attr(void);
> > +int define_roleattribute(void);
> >  int define_filename_trans(void);
> >  int define_sens(void);
> >  int define_te_avtab(int which);
> > diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
> > index 8274d36..d4cc18e 100644
> > --- a/checkpolicy/policy_parse.y
> > +++ b/checkpolicy/policy_parse.y
> > @@ -90,6 +90,8 @@ typedef int (* require_func_t)();
> >  %token INHERITS
> >  %token SID
> >  %token ROLE
> > +%token ROLEATTRIBUTE
> > +%token ATTRIBUTE_ROLE
> >  %token ROLES
> >  %token TYPEALIAS
> >  %token TYPEATTRIBUTE
> > @@ -252,10 +254,13 @@ te_rbac_decl		: te_decl
> >  			| policycap_def
> >  			| ';'
> >                          ;
> > -rbac_decl		: role_type_def
> > +rbac_decl		: attribute_role_def
> > +			| role_type_def
> >                          | role_dominance
> >                          | role_trans_def
> >   			| role_allow_def
> > +			| roleattribute_def
> > +			| role_attr_def
> >  			;
> >  te_decl			: attribute_def
> >                          | type_def
> > @@ -415,10 +420,13 @@ dontaudit_def		: DONTAUDIT names names ':' names names ';'
> >  neverallow_def		: NEVERALLOW names names ':' names names  ';'
> >  			{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
> >  		        ;
> > +attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
> > +			{if (define_attrib_role()) return -1; }
> >  role_type_def		: ROLE identifier TYPES names ';'
> >  			{if (define_role_types()) return -1;}
> > - 			| ROLE identifier';'
> > - 			{if (define_role_types()) return -1;}
> > +			;
> > +role_attr_def		: ROLE identifier opt_attr_list ';'
> > + 			{if (define_role_attr()) return -1;}
> >                          ;
> >  role_dominance		: DOMINANCE '{' roles '}'
> >  			;
> > @@ -440,6 +448,9 @@ role_def		: ROLE identifier_push ';'
> >  			| ROLE identifier_push '{' roles '}'
> >                          {$$ = define_role_dom((role_datum_t*)$4); if ($$ == 0) return -1;}
> >  			;
> > +roleattribute_def	: ROLEATTRIBUTE identifier id_comma_list ';'
> > +			{if (define_roleattribute()) return -1;}
> > +			;
> >  opt_constraints         : constraints
> >                          |
> >                          ;
> > @@ -804,6 +815,7 @@ require_class           : CLASS identifier names
> >  require_decl_def        : ROLE        { $$ = require_role; }
> >                          | TYPE        { $$ = require_type; }
> >                          | ATTRIBUTE   { $$ = require_attribute; }
> > +                        | ATTRIBUTE_ROLE   { $$ = require_attribute_role; }
> >                          | USER        { $$ = require_user; }
> >                          | BOOL        { $$ = require_bool; }
> >                          | SENSITIVITY { $$ = require_sens; }
> > diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
> > index 427c189..b24a087 100644
> > --- a/checkpolicy/policy_scan.l
> > +++ b/checkpolicy/policy_scan.l
> > @@ -76,6 +76,10 @@ ROLE |
> >  role				{ return(ROLE); }
> >  ROLES |
> >  roles				{ return(ROLES); }
> > +ROLEATTRIBUTE |
> > +roleattribute			{ return(ROLEATTRIBUTE);}
> > +ATTRIBUTE_ROLE |
> > +attribute_role			{ return(ATTRIBUTE_ROLE);}
> >  TYPES |
> >  types				{ return(TYPES); }
> >  TYPEALIAS |
> > diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
> > index eebf1a9..b59ab2e 100644
> > --- a/libsepol/include/sepol/policydb/policydb.h
> > +++ b/libsepol/include/sepol/policydb/policydb.h
> > @@ -120,6 +120,10 @@ typedef struct role_datum {
> >  	type_set_t types;	/* set of authorized types for role */
> >  	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
> >  	uint32_t bounds;	/* bounds role, if exist */
> > +#define ROLE_ROLE 0		/* regular role in kernel policies */
> > +#define ROLE_ATTRIB 1		/* attribute */
> > +	uint32_t flavor;
> > +	ebitmap_t roles;	/* roles with this attribute */
> >  } role_datum_t;
> >  
> >  typedef struct role_trans {
> > diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> > index 6d8ff91..feb35ae 100644
> > --- a/libsepol/src/policydb.c
> > +++ b/libsepol/src/policydb.c
> > @@ -350,6 +350,7 @@ void role_datum_init(role_datum_t * x)
> >  	ebitmap_init(&x->dominates);
> >  	type_set_init(&x->types);
> >  	ebitmap_init(&x->cache);
> > +	ebitmap_init(&x->roles);
> >  }
> >  
> >  void role_datum_destroy(role_datum_t * x)
> > @@ -358,6 +359,7 @@ void role_datum_destroy(role_datum_t * x)
> >  		ebitmap_destroy(&x->dominates);
> >  		type_set_destroy(&x->types);
> >  		ebitmap_destroy(&x->cache);
> > +		ebitmap_destroy(&x->roles);
> >  	}
> >  }
> >  
> 
> 
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
 		 	   		  

[-- Attachment #1.2: Type: text/html, Size: 23787 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: v3-0001-Add-role-attribute-support-when-compiling-modules.patch --]
[-- Type: text/x-patch, Size: 16259 bytes --]

From 2657cd72d5569f3b0cb4c3f82bd2f53feeddfcc9 Mon Sep 17 00:00:00 2001
From: Harry Ciao <qingtao.cao@windriver.com>
Date: Sat, 21 May 2011 09:36:03 +0800
Subject: [v3 PATCH 1/6] Add role attribute support when compiling modules.

1. Add a uint32_t "flavor" field and an ebitmap "roles" to the
role_datum_t structure;

2. Add a new "attribute_role" statement and its handler to declare
a role attribute;

3. Modify declare_role() to setup role_datum_t.flavor according
to the isattr argument;

4. Add a new "roleattribute" rule and its handler, which will record
the regular role's (policy value - 1) into the role attribute's
role_datum_t.roles ebitmap;

5. Modify the syntax for the role-types rule only to define the
role-type associations;

6. Add a new role-attr rule to support the declaration of a single
role, and optionally the role attribute that the role belongs to;

7. Check if the new_role used in role-transition rule is a regular role;

8. Support to require a role attribute;

9. Modify symtab_insert() to allow multiple declarations only for
the regular role, while a role attribute can't be declared more than once
and can't share a same name with another regular role.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 checkpolicy/module_compiler.c              |   67 ++++++++++++-
 checkpolicy/module_compiler.h              |    4 +-
 checkpolicy/policy_define.c                |  152 +++++++++++++++++++++++++++-
 checkpolicy/policy_define.h                |    3 +
 checkpolicy/policy_parse.y                 |   18 +++-
 checkpolicy/policy_scan.l                  |    4 +
 libsepol/include/sepol/policydb/policydb.h |    4 +
 libsepol/src/policydb.c                    |   21 ++++
 8 files changed, 265 insertions(+), 8 deletions(-)

diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
index 0946ff6..1c1d1d5 100644
--- a/checkpolicy/module_compiler.c
+++ b/checkpolicy/module_compiler.c
@@ -200,7 +200,7 @@ static int role_implicit_bounds(hashtab_t roles_tab,
 	return 0;
 }
 
-role_datum_t *declare_role(void)
+role_datum_t *declare_role(unsigned char isattr)
 {
 	char *id = queue_remove(id_queue), *dest_id = NULL;
 	role_datum_t *role = NULL, *dest_role = NULL;
@@ -217,7 +217,7 @@ role_datum_t *declare_role(void)
 		return NULL;
 	}
 	role_datum_init(role);
-
+	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
 	retval =
 	    declare_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &value,
 			   &value);
@@ -254,6 +254,7 @@ role_datum_t *declare_role(void)
 			}
 			role_datum_init(dest_role);
 			dest_role->s.value = value;
+			dest_role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
 			if (role_implicit_bounds(roles_tab, dest_id, dest_role)) {
 				free(dest_id);
 				role_datum_destroy(dest_role);
@@ -548,6 +549,55 @@ type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr)
 	return dest_typdatum;
 }
 
+/* Return a role_datum_t for the local avrule_decl with the given ID.
+ * If it does not exist, create one with the same value as 'value'.
+ * This function assumes that the ID is within scope.  c.f.,
+ * is_id_in_scope().
+ *
+ * NOTE: this function usurps ownership of id afterwards.  The caller
+ * shall not reference it nor free() it afterwards.
+ */
+role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr)
+{
+	role_datum_t *dest_roledatum;
+	hashtab_t roles_tab;
+
+	assert(stack_top->type == 1);
+
+	if (stack_top->parent == NULL) {
+		/* in global, so use global symbol table */
+		roles_tab = policydbp->p_roles.table;
+	} else {
+		roles_tab = stack_top->decl->p_roles.table;
+	}
+
+	dest_roledatum = hashtab_search(roles_tab, id);
+	if (!dest_roledatum) {
+		dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t));
+		if (dest_roledatum == NULL) {
+			free(id);
+			return NULL;
+		}
+
+		role_datum_init(dest_roledatum);
+		dest_roledatum->s.value = value;
+		dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
+
+		if (hashtab_insert(roles_tab, id, dest_roledatum)) {
+			free(id);
+			role_datum_destroy(dest_roledatum);
+			free(dest_roledatum);
+			return NULL;
+		}
+	} else {
+		free(id);
+		if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE)
+			return NULL;
+	}
+	
+	return dest_roledatum;
+}
+
 /* Given the current parse stack, returns 1 if a requirement would be
  * allowed here or 0 if not.  For example, the ELSE branch may never
  * have its own requirements.
@@ -812,7 +862,7 @@ int require_class(int pass)
 	return -1;
 }
 
-int require_role(int pass)
+static int require_role_or_attribute(int pass, unsigned char isattr)
 {
 	char *id = queue_remove(id_queue);
 	role_datum_t *role = NULL;
@@ -831,6 +881,7 @@ int require_role(int pass)
 		return -1;
 	}
 	role_datum_init(role);
+	role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
 	retval =
 	    require_symbol(SYM_ROLES, id, (hashtab_datum_t *) role,
 			   &role->s.value, &role->s.value);
@@ -870,6 +921,16 @@ int require_role(int pass)
 	}
 }
 
+int require_role(int pass)
+{
+	return require_role_or_attribute(pass, 0);
+}
+
+int require_attribute_role(int pass)
+{
+	return require_role_or_attribute(pass, 1);
+}
+
 static int require_type_or_attribute(int pass, unsigned char isattr)
 {
 	char *id = queue_remove(id_queue);
diff --git a/checkpolicy/module_compiler.h b/checkpolicy/module_compiler.h
index ae33753..45a21cd 100644
--- a/checkpolicy/module_compiler.h
+++ b/checkpolicy/module_compiler.h
@@ -30,11 +30,12 @@ int declare_symbol(uint32_t symbol_type,
 		   hashtab_key_t key, hashtab_datum_t datum,
 		   uint32_t * dest_value, uint32_t * datum_value);
 
-role_datum_t *declare_role(void);
+role_datum_t *declare_role(unsigned char isattr);
 type_datum_t *declare_type(unsigned char primary, unsigned char isattr);
 user_datum_t *declare_user(void);
 
 type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr);
+role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr);
 
 /* Add a symbol to the current avrule_block's require section.  Note
  * that a module may not both declare and require the same symbol.
@@ -54,6 +55,7 @@ int require_class(int pass);
 int require_role(int pass);
 int require_type(int pass);
 int require_attribute(int pass);
+int require_attribute_role(int pass);
 int require_user(int pass);
 int require_bool(int pass);
 int require_sens(int pass);
diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index f75a682..92646a0 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -1774,6 +1774,9 @@ int define_te_avtab(int which)
 	return 0;
 }
 
+/* The role-types rule is no longer used to declare regular role or
+ * role attribute, but solely aimed for declaring role-types associations.
+ */
 int define_role_types(void)
 {
 	role_datum_t *role;
@@ -1786,9 +1789,25 @@ int define_role_types(void)
 		return 0;
 	}
 
-	if ((role = declare_role()) == NULL) {
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no role name for role-types rule?");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+
+	role = hashtab_search(policydbp->p_roles.table, id);
+	if (!role) {
+		yyerror2("unknown role %s", id);
+		free(id);
 		return -1;
 	}
+
 	while ((id = queue_remove(id_queue))) {
 		if (set_types(&role->types, id, &add, 0))
 			return -1;
@@ -1797,6 +1816,132 @@ int define_role_types(void)
 	return 0;
 }
 
+int define_attrib_role(void)
+{
+	if (pass == 2) {
+		free(queue_remove(id_queue));
+		return 0;
+	}
+
+	/* Declare a role attribute */
+	if (declare_role(TRUE) == NULL)
+		return -1;
+
+	return 0;
+}
+
+int define_role_attr(void)
+{
+	char *id;
+	role_datum_t *r, *attr;
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+	
+	/* Declare a regular role */
+	if ((r = declare_role(FALSE)) == NULL)
+		return -1;
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_ROLES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_roles.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("role attribute %s is not declared", id);
+			free(id);
+			return -1;
+		}
+
+		if (attr->flavor != ROLE_ATTRIB) {
+			yyerror2("%s is a regular role, not an attribute", id);
+			free(id);
+			return -1;
+		}
+
+		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int define_roleattribute(void)
+{
+	char *id;
+	role_datum_t *r, *attr;
+
+	if (pass == 2) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no role name for roleattribute definition?");
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_ROLES, id)) {
+		yyerror2("role %s is not within scope", id);
+		free(id);
+		return -1;
+	}
+	r = hashtab_search(policydbp->p_roles.table, id);
+	if (!r || r->flavor != ROLE_ROLE) {
+		yyerror2("unknown role %s, or not a regular role", id);
+		free(id);
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (!is_id_in_scope(SYM_ROLES, id)) {
+			yyerror2("attribute %s is not within scope", id);
+			free(id);
+			return -1;
+		}
+		attr = hashtab_search(policydbp->p_roles.table, id);
+		if (!attr) {
+			/* treat it as a fatal error */
+			yyerror2("role attribute %s is not declared", id);
+			free(id);
+			return -1;
+		}
+
+		if (attr->flavor != ROLE_ATTRIB) {
+			yyerror2("%s is a regular role, not an attribute", id);
+			free(id);
+			return -1;
+		}
+
+		if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) {
+			yyerror("Out of memory!");
+			return -1;
+		}
+
+		if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) {
+			yyerror("out of memory");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2)
 {
 	role_datum_t *new;
@@ -2138,6 +2283,11 @@ int define_role_trans(int class_specified)
 		goto bad;
 	}
 
+	if (role->flavor != ROLE_ROLE) {
+		yyerror2("the new role %s must be a regular role", id);
+		goto bad;
+	}
+
 	/* This ebitmap business is just to ensure that there are not conflicting role_trans rules */
 	if (role_set_expand(&roles, &e_roles, policydbp, NULL))
 		goto bad;
diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
index 890a6af..fc8cd4d 100644
--- a/checkpolicy/policy_define.h
+++ b/checkpolicy/policy_define.h
@@ -19,6 +19,7 @@ avrule_t *define_cond_te_avtab(int which);
 avrule_t *define_cond_filename_trans(void);
 cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void* arg2);
 int define_attrib(void);
+int define_attrib_role(void);
 int define_av_perms(int inherits);
 int define_bool(void);
 int define_category(void);
@@ -48,6 +49,8 @@ int define_range_trans(int class_specified);
 int define_role_allow(void);
 int define_role_trans(int class_specified);
 int define_role_types(void);
+int define_role_attr(void);
+int define_roleattribute(void);
 int define_filename_trans(void);
 int define_sens(void);
 int define_te_avtab(int which);
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
index 5305ac6..6567369 100644
--- a/checkpolicy/policy_parse.y
+++ b/checkpolicy/policy_parse.y
@@ -90,6 +90,8 @@ typedef int (* require_func_t)();
 %token INHERITS
 %token SID
 %token ROLE
+%token ROLEATTRIBUTE
+%token ATTRIBUTE_ROLE
 %token ROLES
 %token TYPEALIAS
 %token TYPEATTRIBUTE
@@ -253,10 +255,13 @@ te_rbac_decl		: te_decl
 			| policycap_def
 			| ';'
                         ;
-rbac_decl		: role_type_def
+rbac_decl		: attribute_role_def
+			| role_type_def
                         | role_dominance
                         | role_trans_def
  			| role_allow_def
+			| roleattribute_def
+			| role_attr_def
 			;
 te_decl			: attribute_def
                         | type_def
@@ -417,10 +422,13 @@ dontaudit_def		: DONTAUDIT names names ':' names names ';'
 neverallow_def		: NEVERALLOW names names ':' names names  ';'
 			{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
 		        ;
+attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
+			{if (define_attrib_role()) return -1; }
 role_type_def		: ROLE identifier TYPES names ';'
 			{if (define_role_types()) return -1;}
- 			| ROLE identifier';'
- 			{if (define_role_types()) return -1;}
+			;
+role_attr_def		: ROLE identifier opt_attr_list ';'
+ 			{if (define_role_attr()) return -1;}
                         ;
 role_dominance		: DOMINANCE '{' roles '}'
 			;
@@ -442,6 +450,9 @@ role_def		: ROLE identifier_push ';'
 			| ROLE identifier_push '{' roles '}'
                         {$$ = define_role_dom((role_datum_t*)$4); if ($$ == 0) return -1;}
 			;
+roleattribute_def	: ROLEATTRIBUTE identifier id_comma_list ';'
+			{if (define_roleattribute()) return -1;}
+			;
 opt_constraints         : constraints
                         |
                         ;
@@ -803,6 +814,7 @@ require_class           : CLASS identifier names
 require_decl_def        : ROLE        { $$ = require_role; }
                         | TYPE        { $$ = require_type; }
                         | ATTRIBUTE   { $$ = require_attribute; }
+                        | ATTRIBUTE_ROLE   { $$ = require_attribute_role; }
                         | USER        { $$ = require_user; }
                         | BOOL        { $$ = require_bool; }
                         | SENSITIVITY { $$ = require_sens; }
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index 1e7e567..8abc4d9 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -76,6 +76,10 @@ ROLE |
 role				{ return(ROLE); }
 ROLES |
 roles				{ return(ROLES); }
+ROLEATTRIBUTE |
+roleattribute			{ return(ROLEATTRIBUTE);}
+ATTRIBUTE_ROLE |
+attribute_role			{ return(ATTRIBUTE_ROLE);}
 TYPES |
 types				{ return(TYPES); }
 TYPEALIAS |
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index eebf1a9..b59ab2e 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -120,6 +120,10 @@ typedef struct role_datum {
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	uint32_t bounds;	/* bounds role, if exist */
+#define ROLE_ROLE 0		/* regular role in kernel policies */
+#define ROLE_ATTRIB 1		/* attribute */
+	uint32_t flavor;
+	ebitmap_t roles;	/* roles with this attribute */
 } role_datum_t;
 
 typedef struct role_trans {
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 6d8ff91..eb6d590 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -350,6 +350,7 @@ void role_datum_init(role_datum_t * x)
 	ebitmap_init(&x->dominates);
 	type_set_init(&x->types);
 	ebitmap_init(&x->cache);
+	ebitmap_init(&x->roles);
 }
 
 void role_datum_destroy(role_datum_t * x)
@@ -358,6 +359,7 @@ void role_datum_destroy(role_datum_t * x)
 		ebitmap_destroy(&x->dominates);
 		type_set_destroy(&x->types);
 		ebitmap_destroy(&x->cache);
+		ebitmap_destroy(&x->roles);
 	}
 }
 
@@ -1429,6 +1431,25 @@ int symtab_insert(policydb_t * pol, uint32_t sym,
 		if (sym != SYM_ROLES && sym != SYM_USERS) {
 			return -2;
 		}
+		/* Further confine that a role attribute can't have the same
+		 * name as another regular role, and a role attribute can't
+		 * be declared more than once. */
+		if (sym == SYM_ROLES) {
+			role_datum_t *base_role;
+			role_datum_t *cur_role = (role_datum_t *)datum;
+		
+			base_role = (role_datum_t *)
+					hashtab_search(pol->symtab[sym].table,
+						       key);
+			assert(base_role != NULL);
+
+			if (!((base_role->flavor == ROLE_ROLE) &&
+			    (cur_role->flavor == ROLE_ROLE))) {
+				/* Only regular roles are allowed to have
+				 * multiple declarations. */
+				return -2;
+			}
+		}
 	} else if (scope_datum->scope == SCOPE_REQ && scope == SCOPE_DECL) {
 		scope_datum->scope = SCOPE_DECL;
 	} else if (scope_datum->scope != scope) {
-- 
1.7.0.4


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

end of thread, other threads:[~2011-06-26 14:11 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-01  8:57 [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
2011-06-01  8:57 ` [v2 PATCH 1/6] Add role attribute support when compiling modules Harry Ciao
2011-06-24 19:36   ` Steve Lawrence
2011-06-26 14:11     ` HarryCiao
2011-06-01  8:57 ` [v2 PATCH 2/6] Add role attribute support when generating pp files Harry Ciao
2011-06-01  8:57 ` [v2 PATCH 3/6] Add role attribute support when linking modules Harry Ciao
2011-06-01  8:57 ` [v2 PATCH 4/6] Add role attribute support when expanding role_datum_t Harry Ciao
2011-06-01  8:57 ` [v2 PATCH 5/6] Add role attribute support when expanding role_set_t Harry Ciao
2011-06-01  8:57 ` [v2 PATCH 6/6] Support adding one role attribute into another Harry Ciao
2011-06-01  9:51 ` Harry Ciao

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