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