Re: [PATCH 2/2 v2] libsepol, checkpolicy: convert rangetrans and filenametrans to hashtabs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.



[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux