On 11/28/2016 01:29 PM, Stephen Smalley wrote: > range transition and name-based type transition rules were originally > simple unordered lists. They were converted to hashtabs in the kernel > by commit 2f3e82d694d3d7a2db019db1bb63385fbc1066f3 ("selinux: convert range > transition list to a hashtab") and by commit > 2463c26d50adc282d19317013ba0ff473823ca47 ("SELinux: put name based > create rules in a hashtable"), but left unchanged in libsepol and > checkpolicy. Convert libsepol and checkpolicy to use the same hashtabs > as the kernel for the range transitions and name-based type transitions. > > With this change and the preceding one, it is possible to directly compare > a policy file generated by libsepol/checkpolicy and the kernel-generated > /sys/fs/selinux/policy pseudo file after normalizing them both through > checkpolicy. To do so, you can run the following sequence of commands: > > checkpolicy -M -b /etc/selinux/targeted/policy/policy.30 -o policy.1 > checkpolicy -M -b /sys/fs/selinux/policy -o policy.2 > cmp policy.1 policy.2 > > Normalizing the two files via checkpolicy is still necessary to ensure > consistent ordering of the avtab entries. There may still be potential > for other areas of difference, e.g. xperms entries may lack a well-defined > order. > > Signed-off-by: Stephen Smalley <sds@xxxxxxxxxxxxx> NB libqpol in setools4 will need to be updated to build against versions of libsepol that include this change (libsepol 2.7+). > --- > checkpolicy/policy_define.c | 57 ++--- > checkpolicy/test/dispol.c | 36 +++- > libsepol/cil/src/cil_binary.c | 79 ++++--- > libsepol/include/sepol/policydb/context.h | 40 ++++ > libsepol/include/sepol/policydb/policydb.h | 18 +- > libsepol/src/expand.c | 152 +++++++------- > libsepol/src/mls.c | 52 +++-- > libsepol/src/policydb.c | 321 +++++++++++++++++++---------- > libsepol/src/write.c | 177 ++++++++++------ > 9 files changed, 604 insertions(+), 328 deletions(-) > > diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c > index 8b56a29..8647889 100644 > --- a/checkpolicy/policy_define.c > +++ b/checkpolicy/policy_define.c > @@ -3220,11 +3220,12 @@ int define_filename_trans(void) > ebitmap_t e_tclasses; > ebitmap_node_t *snode, *tnode, *cnode; > filename_trans_t *ft; > + filename_trans_datum_t *ftdatum; > filename_trans_rule_t *ftr; > type_datum_t *typdatum; > uint32_t otype; > unsigned int c, s, t; > - int add; > + int add, rc; > > if (pass == 1) { > /* stype */ > @@ -3308,40 +3309,44 @@ int define_filename_trans(void) > ebitmap_for_each_bit(&e_ttypes, tnode, t) { > if (!ebitmap_node_get_bit(tnode, t)) > continue; > - > - for (ft = policydbp->filename_trans; ft; ft = ft->next) { > - if (ft->stype == (s + 1) && > - ft->ttype == (t + 1) && > - ft->tclass == (c + 1) && > - !strcmp(ft->name, name)) { > - yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", > - name, > - policydbp->p_type_val_to_name[s], > - policydbp->p_type_val_to_name[t], > - policydbp->p_class_val_to_name[c]); > - goto bad; > - } > - } > - > - ft = malloc(sizeof(*ft)); > + > + ft = calloc(1, sizeof(*ft)); > if (!ft) { > yyerror("out of memory"); > goto bad; > } > - memset(ft, 0, sizeof(*ft)); > - > - ft->next = policydbp->filename_trans; > - policydbp->filename_trans = ft; > - > + ft->stype = s+1; > + ft->ttype = t+1; > + ft->tclass = c+1; > ft->name = strdup(name); > if (!ft->name) { > yyerror("out of memory"); > goto bad; > } > - ft->stype = s + 1; > - ft->ttype = t + 1; > - ft->tclass = c + 1; > - ft->otype = otype; > + > + ftdatum = hashtab_search(policydbp->filename_trans, > + (hashtab_key_t)ft); > + if (ftdatum) { > + yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", > + name, > + policydbp->p_type_val_to_name[s], > + policydbp->p_type_val_to_name[t], > + policydbp->p_class_val_to_name[c]); > + goto bad; > + } > + > + ftdatum = calloc(1, sizeof(*ftdatum)); > + if (!ftdatum) { > + yyerror("out of memory"); > + goto bad; > + } > + rc = hashtab_insert(policydbp->filename_trans, > + (hashtab_key_t)ft, > + ftdatum); > + if (rc) { > + yyerror("out of memory"); > + goto bad; > + } > } > } > > diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c > index a78ce81..d91fafd 100644 > --- a/checkpolicy/test/dispol.c > +++ b/checkpolicy/test/dispol.c > @@ -330,18 +330,38 @@ static void display_role_trans(policydb_t *p, FILE *fp) > } > } > > +struct filenametr_display_args { > + policydb_t *p; > + FILE *fp; > +}; > + > +static int filenametr_display(hashtab_key_t key, > + hashtab_datum_t datum, > + void *ptr) > +{ > + struct filename_trans *ft = (struct filename_trans *)key; > + struct filename_trans_datum *ftdatum = datum; > + struct filenametr_display_args *args = ptr; > + policydb_t *p = args->p; > + FILE *fp = args->fp; > + > + display_id(p, fp, SYM_TYPES, ft->stype - 1, ""); > + display_id(p, fp, SYM_TYPES, ft->ttype - 1, ""); > + display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":"); > + display_id(p, fp, SYM_TYPES, ftdatum->otype - 1, ""); > + fprintf(fp, " %s\n", ft->name); > + return 0; > +} > + > + > static void display_filename_trans(policydb_t *p, FILE *fp) > { > - filename_trans_t *ft; > + struct filenametr_display_args args; > > fprintf(fp, "filename_trans rules:\n"); > - for (ft = p->filename_trans; ft; ft = ft->next) { > - display_id(p, fp, SYM_TYPES, ft->stype - 1, ""); > - display_id(p, fp, SYM_TYPES, ft->ttype - 1, ""); > - display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":"); > - display_id(p, fp, SYM_TYPES, ft->otype - 1, ""); > - fprintf(fp, " %s\n", ft->name); > - } > + args.p = p; > + args.fp = fp; > + hashtab_map(p->filename_trans, filenametr_display, &args); > } > > int menu(void) > diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c > index a813201..d33981b 100644 > --- a/libsepol/cil/src/cil_binary.c > +++ b/libsepol/cil/src/cil_binary.c > @@ -1131,13 +1131,13 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru > class_datum_t *sepol_obj = NULL; > struct cil_list *class_list; > type_datum_t *sepol_result = NULL; > - filename_trans_t *new = NULL; > + filename_trans_t *newkey = NULL; > + filename_trans_datum_t *newdatum = NULL, *otype = NULL; > ebitmap_t src_bitmap, tgt_bitmap; > ebitmap_node_t *node1, *node2; > unsigned int i, j; > struct cil_list_item *c; > char *name = DATUM(typetrans->name)->name; > - uint32_t *otype = NULL; > > if (name == CIL_KEY_STAR) { > struct cil_type_rule trans; > @@ -1177,20 +1177,20 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru > rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); > if (rc != SEPOL_OK) goto exit; > > - new = cil_malloc(sizeof(*new)); > - memset(new, 0, sizeof(*new)); > - new->stype = sepol_src->s.value; > - new->ttype = sepol_tgt->s.value; > - new->tclass = sepol_obj->s.value; > - new->otype = sepol_result->s.value; > - new->name = cil_strdup(name); > + newkey = cil_calloc(1, sizeof(*newkey)); > + newdatum = cil_calloc(1, sizeof(*newdatum)); > + newkey->stype = sepol_src->s.value; > + newkey->ttype = sepol_tgt->s.value; > + newkey->tclass = sepol_obj->s.value; > + newkey->name = cil_strdup(name); > + newdatum->otype = sepol_result->s.value; > > - rc = hashtab_insert(filename_trans_table, (hashtab_key_t)new, &(new->otype)); > + rc = hashtab_insert(filename_trans_table, (hashtab_key_t)newkey, newdatum); > if (rc != SEPOL_OK) { > if (rc == SEPOL_EEXIST) { > add = CIL_FALSE; > - otype = hashtab_search(filename_trans_table, (hashtab_key_t)new); > - if (new->otype != *otype) { > + otype = hashtab_search(filename_trans_table, (hashtab_key_t)newkey); > + if (newdatum->otype != otype->otype) { > cil_log(CIL_ERR, "Conflicting name type transition rules\n"); > } else { > rc = SEPOL_OK; > @@ -1201,11 +1201,17 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru > } > > if (add == CIL_TRUE) { > - new->next = pdb->filename_trans; > - pdb->filename_trans = new; > + rc = hashtab_insert(pdb->filename_trans, > + (hashtab_key_t)newkey, > + newdatum); > + if (rc != SEPOL_OK) { > + cil_log(CIL_ERR, "Out of memory\n"); > + goto exit; > + } > } else { > - free(new->name); > - free(new); > + free(newkey->name); > + free(newkey); > + free(newdatum); > if (rc != SEPOL_OK) { > goto exit; > } > @@ -2943,7 +2949,8 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st > type_datum_t *sepol_tgt = NULL; > class_datum_t *sepol_class = NULL; > struct cil_list *class_list; > - range_trans_t *new; > + range_trans_t *newkey = NULL; > + struct mls_range *newdatum = NULL; > ebitmap_t src_bitmap, tgt_bitmap; > ebitmap_node_t *node1, *node2; > unsigned int i, j; > @@ -2975,24 +2982,25 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st > rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class); > if (rc != SEPOL_OK) goto exit; > > - new = cil_malloc(sizeof(*new)); > - memset(new, 0, sizeof(range_trans_t)); > - new->source_type = sepol_src->s.value; > - new->target_type = sepol_tgt->s.value; > - new->target_class = sepol_class->s.value; > - rc = __cil_levelrange_to_mls_range(pdb, rangetrans->range, &new->target_range); > + newkey = cil_calloc(1, sizeof(*newkey)); > + newdatum = cil_calloc(1, sizeof(*newdatum)); > + newkey->source_type = sepol_src->s.value; > + newkey->target_type = sepol_tgt->s.value; > + newkey->target_class = sepol_class->s.value; > + rc = __cil_levelrange_to_mls_range(pdb, rangetrans->range, newdatum); > if (rc != SEPOL_OK) { > - free(new); > + free(newkey); > + free(newdatum); > goto exit; > } > > rc = SEPOL_OK; > - rc = hashtab_insert(range_trans_table, (hashtab_key_t)new, &(new->target_range)); > + rc = hashtab_insert(range_trans_table, (hashtab_key_t)newkey, newdatum); > if (rc != SEPOL_OK) { > if (rc == SEPOL_EEXIST) { > add = CIL_FALSE; > - o_range = hashtab_search(range_trans_table, (hashtab_key_t)new); > - if (!mls_range_eq(&new->target_range, o_range)) { > + o_range = hashtab_search(range_trans_table, (hashtab_key_t)newkey); > + if (!mls_range_eq(newdatum, o_range)) { > cil_log(CIL_ERR, "Conflicting Range transition rules\n"); > } else { > rc = SEPOL_OK; > @@ -3003,11 +3011,20 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st > } > > if (add == CIL_TRUE) { > - new->next = pdb->range_tr; > - pdb->range_tr = new; > + rc = hashtab_insert(pdb->range_tr, > + (hashtab_key_t)newkey, > + newdatum); > + if (rc != SEPOL_OK) { > + mls_range_destroy(newdatum); > + free(newdatum); > + free(newkey); > + cil_log(CIL_ERR, "Out of memory\n"); > + goto exit; > + } > } else { > - mls_range_destroy(&new->target_range); > - free(new); > + mls_range_destroy(newdatum); > + free(newdatum); > + free(newkey); > if (rc != SEPOL_OK) { > goto exit; > } > diff --git a/libsepol/include/sepol/policydb/context.h b/libsepol/include/sepol/policydb/context.h > index dbb7c3e..c844c37 100644 > --- a/libsepol/include/sepol/policydb/context.h > +++ b/libsepol/include/sepol/policydb/context.h > @@ -50,6 +50,46 @@ static inline int mls_context_cpy(context_struct_t * dst, > return 0; > } > > +/* > + * Sets both levels in the MLS range of 'dst' to the low level of 'src'. > + */ > +static inline int mls_context_cpy_low(context_struct_t *dst, context_struct_t *src) > +{ > + int rc; > + > + dst->range.level[0].sens = src->range.level[0].sens; > + rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); > + if (rc) > + goto out; > + > + dst->range.level[1].sens = src->range.level[0].sens; > + rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[0].cat); > + if (rc) > + ebitmap_destroy(&dst->range.level[0].cat); > +out: > + return rc; > +} > + > +/* > + * Sets both levels in the MLS range of 'dst' to the high level of 'src'. > + */ > +static inline int mls_context_cpy_high(context_struct_t *dst, context_struct_t *src) > +{ > + int rc; > + > + dst->range.level[0].sens = src->range.level[1].sens; > + rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[1].cat); > + if (rc) > + goto out; > + > + dst->range.level[1].sens = src->range.level[1].sens; > + rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat); > + if (rc) > + ebitmap_destroy(&dst->range.level[0].cat); > +out: > + return rc; > +} > + > static inline int mls_context_cmp(context_struct_t * c1, context_struct_t * c2) > { > return (mls_level_eq(&c1->range.level[0], &c2->range.level[0]) && > diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h > index 77e46fb..31cdd76 100644 > --- a/libsepol/include/sepol/policydb/policydb.h > +++ b/libsepol/include/sepol/policydb/policydb.h > @@ -162,10 +162,12 @@ typedef struct filename_trans { > uint32_t ttype; > uint32_t tclass; > char *name; > - uint32_t otype; > - struct filename_trans *next; > } filename_trans_t; > > +typedef struct filename_trans_datum { > + uint32_t otype; /* expected of new object */ > +} filename_trans_datum_t; > + > /* Type attributes */ > typedef struct type_datum { > symtab_datum_t s; > @@ -218,8 +220,6 @@ typedef struct range_trans { > uint32_t source_type; > uint32_t target_type; > uint32_t target_class; > - mls_range_t target_range; > - struct range_trans *next; > } range_trans_t; > > /* Boolean data type */ > @@ -555,9 +555,6 @@ typedef struct policydb { > /* role transitions */ > role_trans_t *role_tr; > > - /* type transition rules with a 'name' component */ > - filename_trans_t *filename_trans; > - > /* role allows */ > role_allow_t *role_allow; > > @@ -570,8 +567,11 @@ typedef struct policydb { > fixed labeling behavior. */ > genfs_t *genfs; > > - /* range transitions */ > - range_trans_t *range_tr; > + /* range transitions table (range_trans_key -> mls_range) */ > + hashtab_t range_tr; > + > + /* file transitions with the last path component */ > + hashtab_t filename_trans; > > ebitmap_t *type_attr_map; > > diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c > index 7244e01..315fc65 100644 > --- a/libsepol/src/expand.c > +++ b/libsepol/src/expand.c > @@ -1385,10 +1385,12 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) > static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules) > { > unsigned int i, j; > - filename_trans_t *new_trans, *cur_trans; > + filename_trans_t key, *new_trans; > + filename_trans_datum_t *otype; > filename_trans_rule_t *cur_rule; > ebitmap_t stypes, ttypes; > ebitmap_node_t *snode, *tnode; > + int rc; > > cur_rule = rules; > while (cur_rule) { > @@ -1418,40 +1420,32 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r > if (!ebitmap_node_get_bit(tnode, j)) > continue; > > - cur_trans = state->out->filename_trans; > - while (cur_trans) { > - if ((cur_trans->stype == i + 1) && > - (cur_trans->ttype == j + 1) && > - (cur_trans->tclass == cur_rule->tclass) && > - (!strcmp(cur_trans->name, cur_rule->name))) { > - /* duplicate rule, who cares */ > - if (cur_trans->otype == mapped_otype) > - break; > - > - ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\": %s vs %s", > - state->out->p_type_val_to_name[i], > - state->out->p_type_val_to_name[j], > - state->out->p_class_val_to_name[cur_trans->tclass - 1], > - cur_trans->name, > - state->out->p_type_val_to_name[cur_trans->otype - 1], > - state->out->p_type_val_to_name[mapped_otype - 1]); > + key.stype = i + 1; > + key.ttype = j + 1; > + key.tclass = cur_rule->tclass; > + key.name = cur_rule->name; > + otype = hashtab_search(state->out->filename_trans, > + (hashtab_key_t) &key); > + if (otype) { > + /* duplicate rule, ignore */ > + if (otype->otype == mapped_otype) > + continue; > > - return -1; > - } > - cur_trans = cur_trans->next; > + ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\": %s vs %s", > + state->out->p_type_val_to_name[i], > + state->out->p_type_val_to_name[j], > + state->out->p_class_val_to_name[cur_rule->tclass - 1], > + cur_rule->name, > + state->out->p_type_val_to_name[otype->otype - 1], > + state->out->p_type_val_to_name[mapped_otype - 1]); > + return -1; > } > - /* duplicate rule, who cares */ > - if (cur_trans) > - continue; > > - new_trans = malloc(sizeof(*new_trans)); > + new_trans = calloc(1, sizeof(*new_trans)); > if (!new_trans) { > ERR(state->handle, "Out of memory!"); > return -1; > } > - memset(new_trans, 0, sizeof(*new_trans)); > - new_trans->next = state->out->filename_trans; > - state->out->filename_trans = new_trans; > > new_trans->name = strdup(cur_rule->name); > if (!new_trans->name) { > @@ -1461,7 +1455,21 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r > new_trans->stype = i + 1; > new_trans->ttype = j + 1; > new_trans->tclass = cur_rule->tclass; > - new_trans->otype = mapped_otype; > + > + otype = calloc(1, sizeof(*otype)); > + if (!otype) { > + ERR(state->handle, "Out of memory!"); > + return -1; > + } > + otype->otype = mapped_otype; > + > + rc = hashtab_insert(state->out->filename_trans, > + (hashtab_key_t)new_trans, > + otype); > + if (rc) { > + ERR(state->handle, "Out of memory!"); > + return -1; > + } > } > } > > @@ -1477,63 +1485,67 @@ static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t tclass, > mls_semantic_range_t * trange, > expand_state_t * state) > { > - range_trans_t *rt, *check_rt = state->out->range_tr; > - mls_range_t exp_range; > + range_trans_t *rt = NULL, key; > + mls_range_t *r, *exp_range = NULL; > int rc = -1; > > - if (mls_semantic_range_expand(trange, &exp_range, state->out, > + exp_range = calloc(1, sizeof(*exp_range)); > + if (!exp_range) { > + ERR(state->handle, "Out of memory!"); > + return -1; > + } > + > + if (mls_semantic_range_expand(trange, exp_range, state->out, > state->handle)) > - goto out; > + goto err; > > /* check for duplicates/conflicts */ > - while (check_rt) { > - if ((check_rt->source_type == stype) && > - (check_rt->target_type == ttype) && > - (check_rt->target_class == tclass)) { > - if (mls_range_eq(&check_rt->target_range, &exp_range)) { > - /* duplicate */ > - break; > - } else { > - /* conflict */ > - ERR(state->handle, > - "Conflicting range trans rule %s %s : %s", > - state->out->p_type_val_to_name[stype - 1], > - state->out->p_type_val_to_name[ttype - 1], > - state->out->p_class_val_to_name[tclass - > - 1]); > - goto out; > - } > - } > - check_rt = check_rt->next; > - } > - if (check_rt) { > - /* this is a dup - skip */ > - rc = 0; > - goto out; > + key.source_type = stype; > + key.target_type = ttype; > + key.target_class = tclass; > + r = hashtab_search(state->out->range_tr, (hashtab_key_t) &key); > + if (r) { > + if (mls_range_eq(r, exp_range)) { > + /* duplicate, ignore */ > + mls_range_destroy(exp_range); > + free(exp_range); > + return 0; > + } > + > + /* conflict */ > + ERR(state->handle, > + "Conflicting range trans rule %s %s : %s", > + state->out->p_type_val_to_name[stype - 1], > + state->out->p_type_val_to_name[ttype - 1], > + state->out->p_class_val_to_name[tclass - 1]); > + goto err; > } > > - rt = (range_trans_t *) calloc(1, sizeof(range_trans_t)); > + rt = calloc(1, sizeof(*rt)); > if (!rt) { > ERR(state->handle, "Out of memory!"); > - goto out; > + goto err; > } > - > - rt->next = state->out->range_tr; > - state->out->range_tr = rt; > - > rt->source_type = stype; > rt->target_type = ttype; > rt->target_class = tclass; > - if (mls_range_cpy(&rt->target_range, &exp_range)) { > + > + rc = hashtab_insert(state->out->range_tr, (hashtab_key_t) rt, > + exp_range); > + if (rc) { > ERR(state->handle, "Out of memory!"); > - goto out; > - } > + goto err; > > - rc = 0; > + } > > - out: > - mls_range_destroy(&exp_range); > - return rc; > + return 0; > +err: > + free(rt); > + if (exp_range) { > + mls_range_destroy(exp_range); > + free(exp_range); > + } > + return -1; > } > > static int expand_range_trans(expand_state_t * state, > diff --git a/libsepol/src/mls.c b/libsepol/src/mls.c > index 8047d91..be85475 100644 > --- a/libsepol/src/mls.c > +++ b/libsepol/src/mls.c > @@ -610,22 +610,45 @@ int mls_compute_sid(policydb_t * policydb, > sepol_security_class_t tclass, > uint32_t specified, context_struct_t * newcontext) > { > - range_trans_t *rtr; > + range_trans_t rtr; > + struct mls_range *r; > + struct class_datum *cladatum; > + int default_range = 0; > + > if (!policydb->mls) > return 0; > > switch (specified) { > case AVTAB_TRANSITION: > /* Look for a range transition rule. */ > - for (rtr = policydb->range_tr; rtr; rtr = rtr->next) { > - if (rtr->source_type == scontext->type && > - rtr->target_type == tcontext->type && > - rtr->target_class == tclass) { > - /* Set the range from the rule */ > - return mls_range_set(newcontext, > - &rtr->target_range); > - } > + rtr.source_type = scontext->type; > + rtr.target_type = tcontext->type; > + rtr.target_class = tclass; > + r = hashtab_search(policydb->range_tr, (hashtab_key_t) &rtr); > + if (r) > + return mls_range_set(newcontext, r); > + > + if (tclass && tclass <= policydb->p_classes.nprim) { > + cladatum = policydb->class_val_to_struct[tclass - 1]; > + if (cladatum) > + default_range = cladatum->default_range; > + } > + > + switch (default_range) { > + case DEFAULT_SOURCE_LOW: > + return mls_context_cpy_low(newcontext, scontext); > + case DEFAULT_SOURCE_HIGH: > + return mls_context_cpy_high(newcontext, scontext); > + case DEFAULT_SOURCE_LOW_HIGH: > + return mls_context_cpy(newcontext, scontext); > + case DEFAULT_TARGET_LOW: > + return mls_context_cpy_low(newcontext, tcontext); > + case DEFAULT_TARGET_HIGH: > + return mls_context_cpy_high(newcontext, tcontext); > + case DEFAULT_TARGET_LOW_HIGH: > + return mls_context_cpy(newcontext, tcontext); > } > + > /* Fallthrough */ > case AVTAB_CHANGE: > if (tclass == SECCLASS_PROCESS) > @@ -635,15 +658,8 @@ int mls_compute_sid(policydb_t * policydb, > /* Use the process effective MLS attributes. */ > return mls_scopy_context(newcontext, scontext); > case AVTAB_MEMBER: > - /* Only polyinstantiate the MLS attributes if > - the type is being polyinstantiated */ > - if (newcontext->type != tcontext->type) { > - /* Use the process effective MLS attributes. */ > - return mls_scopy_context(newcontext, scontext); > - } else { > - /* Use the related object MLS attributes. */ > - return mls_copy_context(newcontext, tcontext); > - } > + /* Use the process effective MLS attributes. */ > + return mls_context_cpy_low(newcontext, scontext); > default: > return -EINVAL; > } > diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c > index f9b2ec3..142bad8 100644 > --- a/libsepol/src/policydb.c > +++ b/libsepol/src/policydb.c > @@ -721,6 +721,77 @@ static int roles_init(policydb_t * p) > goto out; > } > > +static inline unsigned long > +partial_name_hash(unsigned long c, unsigned long prevhash) > +{ > + return (prevhash + (c << 4) + (c >> 4)) * 11; > +} > + > +static unsigned int filenametr_hash(hashtab_t h, hashtab_key_t k) > +{ > + const struct filename_trans *ft = (const struct filename_trans *)k; > + unsigned long hash; > + unsigned int byte_num; > + unsigned char focus; > + > + hash = ft->stype ^ ft->ttype ^ ft->tclass; > + > + byte_num = 0; > + while ((focus = ft->name[byte_num++])) > + hash = partial_name_hash(focus, hash); > + return hash & (h->size - 1); > +} > + > +static int filenametr_cmp(hashtab_t h __attribute__ ((unused)), > + hashtab_key_t k1, hashtab_key_t k2) > +{ > + const struct filename_trans *ft1 = (const struct filename_trans *)k1; > + const struct filename_trans *ft2 = (const struct filename_trans *)k2; > + int v; > + > + v = ft1->stype - ft2->stype; > + if (v) > + return v; > + > + v = ft1->ttype - ft2->ttype; > + if (v) > + return v; > + > + v = ft1->tclass - ft2->tclass; > + if (v) > + return v; > + > + return strcmp(ft1->name, ft2->name); > + > +} > + > +static unsigned int rangetr_hash(hashtab_t h, hashtab_key_t k) > +{ > + const struct range_trans *key = (const struct range_trans *)k; > + return (key->source_type + (key->target_type << 3) + > + (key->target_class << 5)) & (h->size - 1); > +} > + > +static int rangetr_cmp(hashtab_t h __attribute__ ((unused)), > + hashtab_key_t k1, hashtab_key_t k2) > +{ > + const struct range_trans *key1 = (const struct range_trans *)k1; > + const struct range_trans *key2 = (const struct range_trans *)k2; > + int v; > + > + v = key1->source_type - key2->source_type; > + if (v) > + return v; > + > + v = key1->target_type - key2->target_type; > + if (v) > + return v; > + > + v = key1->target_class - key2->target_class; > + > + return v; > +} > + > /* > * Initialize a policy database structure. > */ > @@ -730,50 +801,62 @@ int policydb_init(policydb_t * p) > > memset(p, 0, sizeof(policydb_t)); > > - ebitmap_init(&p->policycaps); > - > - ebitmap_init(&p->permissive_map); > - > for (i = 0; i < SYM_NUM; i++) { > p->sym_val_to_name[i] = NULL; > rc = symtab_init(&p->symtab[i], symtab_sizes[i]); > if (rc) > - goto out_free_symtab; > + goto err; > } > > /* initialize the module stuff */ > for (i = 0; i < SYM_NUM; i++) { > if (symtab_init(&p->scope[i], symtab_sizes[i])) { > - goto out_free_symtab; > + goto err; > } > } > if ((p->global = avrule_block_create()) == NULL || > (p->global->branch_list = avrule_decl_create(1)) == NULL) { > - goto out_free_symtab; > + goto err; > } > p->decl_val_to_struct = NULL; > > rc = avtab_init(&p->te_avtab); > if (rc) > - goto out_free_symtab; > + goto err; > > rc = roles_init(p); > if (rc) > - goto out_free_symtab; > + goto err; > > rc = cond_policydb_init(p); > if (rc) > - goto out_free_symtab; > - out: > - return rc; > + goto err; > + > + p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); > + if (!p->filename_trans) { > + rc = -ENOMEM; > + goto err; > + } > > - out_free_symtab: > + p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); > + if (!p->range_tr) { > + rc = -ENOMEM; > + goto err; > + } > + > + ebitmap_init(&p->policycaps); > + ebitmap_init(&p->permissive_map); > + > + return 0; > +err: > + hashtab_destroy(p->filename_trans); > + hashtab_destroy(p->range_tr); > for (i = 0; i < SYM_NUM; i++) { > hashtab_destroy(p->symtab[i].table); > hashtab_destroy(p->scope[i].table); > } > avrule_block_list_destroy(p->global); > - goto out; > + return rc; > } > > int policydb_role_cache(hashtab_key_t key > @@ -1242,6 +1325,27 @@ static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, > common_destroy, class_destroy, role_destroy, type_destroy, user_destroy, > cond_destroy_bool, sens_destroy, cat_destroy,}; > > +static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum, > + void *p __attribute__ ((unused))) > +{ > + struct filename_trans *ft = (struct filename_trans *)key; > + free(ft->name); > + free(key); > + free(datum); > + return 0; > +} > + > +static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum, > + void *p __attribute__ ((unused))) > +{ > + struct mls_range *rt = (struct mls_range *)datum; > + free(key); > + ebitmap_destroy(&rt->level[0].cat); > + ebitmap_destroy(&rt->level[1].cat); > + free(datum); > + return 0; > +} > + > void ocontext_selinux_free(ocontext_t **ocontexts) > { > ocontext_t *c, *ctmp; > @@ -1291,8 +1395,6 @@ void policydb_destroy(policydb_t * p) > unsigned int i; > role_allow_t *ra, *lra = NULL; > role_trans_t *tr, *ltr = NULL; > - range_trans_t *rt, *lrt = NULL; > - filename_trans_t *ft, *nft; > > if (!p) > return; > @@ -1358,14 +1460,6 @@ void policydb_destroy(policydb_t * p) > if (ltr) > free(ltr); > > - ft = p->filename_trans; > - while (ft) { > - nft = ft->next; > - free(ft->name); > - free(ft); > - ft = nft; > - } > - > for (ra = p->role_allow; ra; ra = ra->next) { > if (lra) > free(lra); > @@ -1374,19 +1468,11 @@ void policydb_destroy(policydb_t * p) > if (lra) > free(lra); > > - for (rt = p->range_tr; rt; rt = rt->next) { > - if (lrt) { > - ebitmap_destroy(&lrt->target_range.level[0].cat); > - ebitmap_destroy(&lrt->target_range.level[1].cat); > - free(lrt); > - } > - lrt = rt; > - } > - if (lrt) { > - ebitmap_destroy(&lrt->target_range.level[0].cat); > - ebitmap_destroy(&lrt->target_range.level[1].cat); > - free(lrt); > - } > + hashtab_map(p->filename_trans, filenametr_destroy, NULL); > + hashtab_destroy(p->filename_trans); > + > + hashtab_map(p->range_tr, range_tr_destroy, NULL); > + hashtab_destroy(p->range_tr); > > if (p->type_attr_map) { > for (i = 0; i < p->p_types.nprim; i++) { > @@ -2428,11 +2514,12 @@ int role_allow_read(role_allow_t ** r, struct policy_file *fp) > return 0; > } > > -int filename_trans_read(filename_trans_t **t, struct policy_file *fp) > +int filename_trans_read(policydb_t *p, struct policy_file *fp) > { > unsigned int i; > uint32_t buf[4], nel, len; > - filename_trans_t *ft, *lft; > + filename_trans_t *ft; > + filename_trans_datum_t *otype; > int rc; > char *name; > > @@ -2441,43 +2528,73 @@ int filename_trans_read(filename_trans_t **t, struct policy_file *fp) > return -1; > nel = le32_to_cpu(buf[0]); > > - lft = NULL; > for (i = 0; i < nel; i++) { > - ft = calloc(1, sizeof(struct filename_trans)); > + ft = NULL; > + otype = NULL; > + name = NULL; > + > + ft = calloc(1, sizeof(*ft)); > if (!ft) > - return -1; > - if (lft) > - lft->next = ft; > - else > - *t = ft; > - lft = ft; > + goto err; > + otype = calloc(1, sizeof(*otype)); > + if (!ft) > + goto err; > rc = next_entry(buf, fp, sizeof(uint32_t)); > if (rc < 0) > - return -1; > + goto err; > len = le32_to_cpu(buf[0]); > if (zero_or_saturated(len)) > - return -1; > + goto err; > > name = calloc(len + 1, sizeof(*name)); > if (!name) > - return -1; > + goto err; > > ft->name = name; > > rc = next_entry(name, fp, len); > if (rc < 0) > - return -1; > + goto err; > > rc = next_entry(buf, fp, sizeof(uint32_t) * 4); > if (rc < 0) > - return -1; > + goto err; > > ft->stype = le32_to_cpu(buf[0]); > ft->ttype = le32_to_cpu(buf[1]); > ft->tclass = le32_to_cpu(buf[2]); > - ft->otype = le32_to_cpu(buf[3]); > + otype->otype = le32_to_cpu(buf[3]); > + > + rc = hashtab_insert(p->filename_trans, (hashtab_key_t) ft, > + otype); > + if (rc) { > + if (rc != SEPOL_EEXIST) > + goto err; > + /* > + * Some old policies were wrongly generated with > + * duplicate filename transition rules. For backward > + * compatibility, do not reject such policies, just > + * issue a warning and ignore the duplicate. > + */ > + WARN(fp->handle, > + "Duplicate name-based type_transition %s %s:%s \"%s\": %s, ignoring", > + p->p_type_val_to_name[ft->stype - 1], > + p->p_type_val_to_name[ft->ttype - 1], > + p->p_class_val_to_name[ft->tclass - 1], > + ft->name, > + p->p_type_val_to_name[otype->otype - 1]); > + free(ft); > + free(name); > + free(otype); > + /* continue, ignoring this one */ > + } > } > return 0; > +err: > + free(ft); > + free(otype); > + free(name); > + return -1; > } > > static int ocontext_read_xen(struct policydb_compat_info *info, > @@ -3129,8 +3246,9 @@ static avrule_t *avrule_read(policydb_t * p > static int range_read(policydb_t * p, struct policy_file *fp) > { > uint32_t buf[2], nel; > - range_trans_t *rt, *lrt; > - range_trans_rule_t *rtr, *lrtr = NULL; > + range_trans_t *rt = NULL; > + struct mls_range *r = NULL; > + range_trans_rule_t *rtr = NULL, *lrtr = NULL; > unsigned int i; > int new_rangetr = (p->policy_type == POLICY_KERN && > p->policyvers >= POLICYDB_VERSION_RANGETRANS); > @@ -3140,84 +3258,79 @@ static int range_read(policydb_t * p, struct policy_file *fp) > if (rc < 0) > return -1; > nel = le32_to_cpu(buf[0]); > - lrt = NULL; > for (i = 0; i < nel; i++) { > rt = calloc(1, sizeof(range_trans_t)); > if (!rt) > return -1; > - if (lrt) > - lrt->next = rt; > - else > - p->range_tr = rt; > rc = next_entry(buf, fp, (sizeof(uint32_t) * 2)); > if (rc < 0) > - return -1; > + goto err; > rt->source_type = le32_to_cpu(buf[0]); > rt->target_type = le32_to_cpu(buf[1]); > if (new_rangetr) { > rc = next_entry(buf, fp, (sizeof(uint32_t))); > if (rc < 0) > - return -1; > + goto err; > rt->target_class = le32_to_cpu(buf[0]); > } else > rt->target_class = SECCLASS_PROCESS; > - if (mls_read_range_helper(&rt->target_range, fp)) > - return -1; > - lrt = rt; > - } > - > - /* if this is a kernel policy, we are done - otherwise we need to > - * convert these structs to range_trans_rule_ts */ > - if (p->policy_type == POLICY_KERN) > - return 0; > + r = calloc(1, sizeof(*r)); > + if (!r) > + goto err; > + if (mls_read_range_helper(r, fp)) > + goto err; > + > + if (p->policy_type == POLICY_KERN) { > + rc = hashtab_insert(p->range_tr, (hashtab_key_t)rt, r); > + if (rc) > + goto err; > + rt = NULL; > + r = NULL; > + continue; > + } > > - /* create range_trans_rules_ts that correspond to the range_trans_ts > - * that were just read in from an older policy */ > - for (rt = p->range_tr; rt; rt = rt->next) { > + /* Module policy: convert to range_trans_rule and discard. */ > rtr = malloc(sizeof(range_trans_rule_t)); > - if (!rtr) { > - return -1; > - } > + if (!rtr) > + goto err; > range_trans_rule_init(rtr); > > - if (lrtr) > - lrtr->next = rtr; > - else > - p->global->enabled->range_tr_rules = rtr; > - > if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1)) > - return -1; > + goto err; > > if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1)) > - return -1; > + goto err; > > if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1)) > - return -1; > + goto err; > > - if (mls_range_to_semantic(&rt->target_range, &rtr->trange)) > - return -1; > + if (mls_range_to_semantic(r, &rtr->trange)) > + goto err; > + > + if (lrtr) > + lrtr->next = rtr; > + else > + p->global->enabled->range_tr_rules = rtr; > > + free(rt); > + rt = NULL; > + free(r); > + r = NULL; > lrtr = rtr; > } > > - /* now destroy the range_trans_ts */ > - lrt = NULL; > - for (rt = p->range_tr; rt; rt = rt->next) { > - if (lrt) { > - ebitmap_destroy(&lrt->target_range.level[0].cat); > - ebitmap_destroy(&lrt->target_range.level[1].cat); > - free(lrt); > - } > - lrt = rt; > + return 0; > +err: > + free(rt); > + if (r) { > + mls_range_destroy(r); > + free(r); > } > - if (lrt) { > - ebitmap_destroy(&lrt->target_range.level[0].cat); > - ebitmap_destroy(&lrt->target_range.level[1].cat); > - free(lrt); > + if (rtr) { > + range_trans_rule_destroy(rtr); > + free(rtr); > } > - p->range_tr = NULL; > - > - return 0; > + return -1; > } > > int avrule_read_list(policydb_t * p, avrule_t ** avrules, > @@ -3904,7 +4017,7 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose) > if (role_allow_read(&p->role_allow, fp)) > goto bad; > if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS && > - filename_trans_read(&p->filename_trans, fp)) > + filename_trans_read(p, fp)) > goto bad; > } else { > /* first read the AV rule blocks, then the scope tables */ > diff --git a/libsepol/src/write.c b/libsepol/src/write.c > index fbc6dad..c4c84ac 100644 > --- a/libsepol/src/write.c > +++ b/libsepol/src/write.c > @@ -563,40 +563,55 @@ static int role_allow_write(role_allow_t * r, struct policy_file *fp) > return POLICYDB_SUCCESS; > } > > -static int filename_trans_write(filename_trans_t * r, struct policy_file *fp) > +static int filename_write_helper(hashtab_key_t key, void *data, void *ptr) > { > - filename_trans_t *ft; > uint32_t buf[4]; > - size_t nel, items, len; > + size_t items, len; > + struct filename_trans *ft = (struct filename_trans *)key; > + struct filename_trans_datum *otype = data; > + void *fp = ptr; > > - nel = 0; > - for (ft = r; ft; ft = ft->next) > - nel++; > - buf[0] = cpu_to_le32(nel); > + len = strlen(ft->name); > + buf[0] = cpu_to_le32(len); > items = put_entry(buf, sizeof(uint32_t), 1, fp); > if (items != 1) > return POLICYDB_ERROR; > - for (ft = r; ft; ft = ft->next) { > - len = strlen(ft->name); > - buf[0] = cpu_to_le32(len); > - items = put_entry(buf, sizeof(uint32_t), 1, fp); > - if (items != 1) > - return POLICYDB_ERROR; > > - items = put_entry(ft->name, sizeof(char), len, fp); > - if (items != len) > - return POLICYDB_ERROR; > + items = put_entry(ft->name, sizeof(char), len, fp); > + if (items != len) > + return POLICYDB_ERROR; > > - buf[0] = cpu_to_le32(ft->stype); > - buf[1] = cpu_to_le32(ft->ttype); > - buf[2] = cpu_to_le32(ft->tclass); > - buf[3] = cpu_to_le32(ft->otype); > - items = put_entry(buf, sizeof(uint32_t), 4, fp); > - if (items != 4) > - return POLICYDB_ERROR; > - } > + buf[0] = cpu_to_le32(ft->stype); > + buf[1] = cpu_to_le32(ft->ttype); > + buf[2] = cpu_to_le32(ft->tclass); > + buf[3] = cpu_to_le32(otype->otype); > + items = put_entry(buf, sizeof(uint32_t), 4, fp); > + if (items != 4) > + return POLICYDB_ERROR; > > - return POLICYDB_SUCCESS; > + return 0; > +} > + > +static int filename_trans_write(struct policydb *p, void *fp) > +{ > + size_t nel, items; > + uint32_t buf[1]; > + int rc; > + > + if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) > + return 0; > + > + nel = p->filename_trans->nel; > + buf[0] = cpu_to_le32(nel); > + items = put_entry(buf, sizeof(uint32_t), 1, fp); > + if (items != 1) > + return POLICYDB_ERROR; > + > + rc = hashtab_map(p->filename_trans, filename_write_helper, fp); > + if (rc) > + return rc; > + > + return 0; > } > > static int role_set_write(role_set_t * x, struct policy_file *fp) > @@ -1512,51 +1527,89 @@ static int genfs_write(policydb_t * p, struct policy_file *fp) > return POLICYDB_SUCCESS; > } > > + > +struct rangetrans_write_args { > + size_t nel; > + int new_rangetr; > + struct policy_file *fp; > +}; > + > +static int rangetrans_count(hashtab_key_t key, > + void *data __attribute__ ((unused)), > + void *ptr) > +{ > + struct range_trans *rt = (struct range_trans *)key; > + struct rangetrans_write_args *args = ptr; > + > + /* all range_transitions are written for the new format, only > + process related range_transitions are written for the old > + format, so count accordingly */ > + if (args->new_rangetr || rt->target_class == SECCLASS_PROCESS) > + args->nel++; > + return 0; > +} > + > +static int range_write_helper(hashtab_key_t key, void *data, void *ptr) > +{ > + uint32_t buf[2]; > + struct range_trans *rt = (struct range_trans *)key; > + struct mls_range *r = data; > + struct rangetrans_write_args *args = ptr; > + struct policy_file *fp = args->fp; > + int new_rangetr = args->new_rangetr; > + size_t items; > + static int warning_issued = 0; > + int rc; > + > + if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) { > + if (!warning_issued) > + WARN(fp->handle, "Discarding range_transition " > + "rules for security classes other than " > + "\"process\""); > + warning_issued = 1; > + return 0; > + } > + > + buf[0] = cpu_to_le32(rt->source_type); > + buf[1] = cpu_to_le32(rt->target_type); > + items = put_entry(buf, sizeof(uint32_t), 2, fp); > + if (items != 2) > + return POLICYDB_ERROR; > + if (new_rangetr) { > + buf[0] = cpu_to_le32(rt->target_class); > + items = put_entry(buf, sizeof(uint32_t), 1, fp); > + if (items != 1) > + return POLICYDB_ERROR; > + } > + rc = mls_write_range_helper(r, fp); > + if (rc) > + return rc; > + > + return 0; > +} > + > static int range_write(policydb_t * p, struct policy_file *fp) > { > - size_t nel, items; > - struct range_trans *rt; > + size_t items; > uint32_t buf[2]; > int new_rangetr = (p->policy_type == POLICY_KERN && > p->policyvers >= POLICYDB_VERSION_RANGETRANS); > - int warning_issued = 0; > + struct rangetrans_write_args args; > + int rc; > > - nel = 0; > - for (rt = p->range_tr; rt; rt = rt->next) { > - /* all range_transitions are written for the new format, only > - process related range_transitions are written for the old > - format, so count accordingly */ > - if (new_rangetr || rt->target_class == SECCLASS_PROCESS) > - nel++; > - } > - buf[0] = cpu_to_le32(nel); > + args.nel = 0; > + args.new_rangetr = new_rangetr; > + args.fp = fp; > + rc = hashtab_map(p->range_tr, rangetrans_count, &args); > + if (rc) > + return rc; > + > + buf[0] = cpu_to_le32(args.nel); > items = put_entry(buf, sizeof(uint32_t), 1, fp); > if (items != 1) > return POLICYDB_ERROR; > - for (rt = p->range_tr; rt; rt = rt->next) { > - if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) { > - if (!warning_issued) > - WARN(fp->handle, "Discarding range_transition " > - "rules for security classes other than " > - "\"process\""); > - warning_issued = 1; > - continue; > - } > - buf[0] = cpu_to_le32(rt->source_type); > - buf[1] = cpu_to_le32(rt->target_type); > - items = put_entry(buf, sizeof(uint32_t), 2, fp); > - if (items != 2) > - return POLICYDB_ERROR; > - if (new_rangetr) { > - buf[0] = cpu_to_le32(rt->target_class); > - items = put_entry(buf, sizeof(uint32_t), 1, fp); > - if (items != 1) > - return POLICYDB_ERROR; > - } > - if (mls_write_range_helper(&rt->target_range, fp)) > - return POLICYDB_ERROR; > - } > - return POLICYDB_SUCCESS; > + > + return hashtab_map(p->range_tr, range_write_helper, &args); > } > > /************** module writing functions below **************/ > @@ -2136,7 +2189,7 @@ int policydb_write(policydb_t * p, struct policy_file *fp) > if (role_allow_write(p->role_allow, fp)) > return POLICYDB_ERROR; > if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) { > - if (filename_trans_write(p->filename_trans, fp)) > + if (filename_trans_write(p, fp)) > return POLICYDB_ERROR; > } else { > if (p->filename_trans) > _______________________________________________ Selinux mailing list Selinux@xxxxxxxxxxxxx To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx. To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.