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@xxxxxxxxxxxxx> > --- > 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@xxxxxxxxxxxxx with the words "unsubscribe selinux" without quotes as the message.