diff options
Diffstat (limited to 'security/selinux/ss/policydb.c')
| -rw-r--r-- | security/selinux/ss/policydb.c | 1120 | 
1 files changed, 738 insertions, 382 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 94f630d93a5..9c5cdc2caae 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -13,7 +13,7 @@   *   *	Added conditional policy language extensions   * - * Updated: Hewlett-Packard <paul.moore@hp.com> + * Updated: Hewlett-Packard <paul@paul-moore.com>   *   *      Added support for the policy capability bitmap   * @@ -123,6 +123,31 @@ static struct policydb_compat_info policydb_compat[] = {  		.sym_num	= SYM_NUM,  		.ocon_num	= OCON_NUM,  	}, +	{ +		.version	= POLICYDB_VERSION_FILENAME_TRANS, +		.sym_num	= SYM_NUM, +		.ocon_num	= OCON_NUM, +	}, +	{ +		.version	= POLICYDB_VERSION_ROLETRANS, +		.sym_num	= SYM_NUM, +		.ocon_num	= OCON_NUM, +	}, +	{ +		.version	= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, +		.sym_num	= SYM_NUM, +		.ocon_num	= OCON_NUM, +	}, +	{ +		.version	= POLICYDB_VERSION_DEFAULT_TYPE, +		.sym_num	= SYM_NUM, +		.ocon_num	= OCON_NUM, +	}, +	{ +		.version	= POLICYDB_VERSION_CONSTRAINT_NAMES, +		.sym_num	= SYM_NUM, +		.ocon_num	= OCON_NUM, +	},  };  static struct policydb_compat_info *policydb_lookup_compat(int version) @@ -148,32 +173,67 @@ static int roles_init(struct policydb *p)  	int rc;  	struct role_datum *role; +	rc = -ENOMEM;  	role = kzalloc(sizeof(*role), GFP_KERNEL); -	if (!role) { -		rc = -ENOMEM; +	if (!role)  		goto out; -	} + +	rc = -EINVAL;  	role->value = ++p->p_roles.nprim; -	if (role->value != OBJECT_R_VAL) { -		rc = -EINVAL; -		goto out_free_role; -	} +	if (role->value != OBJECT_R_VAL) +		goto out; + +	rc = -ENOMEM;  	key = kstrdup(OBJECT_R, GFP_KERNEL); -	if (!key) { -		rc = -ENOMEM; -		goto out_free_role; -	} +	if (!key) +		goto out; +  	rc = hashtab_insert(p->p_roles.table, key, role);  	if (rc) -		goto out_free_key; -out: -	return rc; +		goto out; -out_free_key: +	return 0; +out:  	kfree(key); -out_free_role:  	kfree(role); -	goto out; +	return rc; +} + +static u32 filenametr_hash(struct hashtab *h, const void *k) +{ +	const struct filename_trans *ft = 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(struct hashtab *h, const void *k1, const void *k2) +{ +	const struct filename_trans *ft1 = k1; +	const struct filename_trans *ft2 = 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 u32 rangetr_hash(struct hashtab *h, const void *k) @@ -213,35 +273,40 @@ static int policydb_init(struct policydb *p)  	for (i = 0; i < SYM_NUM; i++) {  		rc = symtab_init(&p->symtab[i], symtab_sizes[i]);  		if (rc) -			goto out_free_symtab; +			goto out;  	}  	rc = avtab_init(&p->te_avtab);  	if (rc) -		goto out_free_symtab; +		goto out;  	rc = roles_init(p);  	if (rc) -		goto out_free_symtab; +		goto out;  	rc = cond_policydb_init(p);  	if (rc) -		goto out_free_symtab; +		goto out; + +	p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); +	if (!p->filename_trans) +		goto out;  	p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);  	if (!p->range_tr) -		goto out_free_symtab; +		goto out; +	ebitmap_init(&p->filename_trans_ttypes);  	ebitmap_init(&p->policycaps);  	ebitmap_init(&p->permissive_map); +	return 0;  out: -	return rc; - -out_free_symtab: +	hashtab_destroy(p->filename_trans); +	hashtab_destroy(p->range_tr);  	for (i = 0; i < SYM_NUM; i++)  		hashtab_destroy(p->symtab[i].table); -	goto out; +	return rc;  }  /* @@ -258,12 +323,17 @@ static int common_index(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct common_datum *comdatum; +	struct flex_array *fa;  	comdatum = datum;  	p = datap;  	if (!comdatum->value || comdatum->value > p->p_commons.nprim)  		return -EINVAL; -	p->p_common_val_to_name[comdatum->value - 1] = key; + +	fa = p->sym_val_to_name[SYM_COMMONS]; +	if (flex_array_put_ptr(fa, comdatum->value - 1, key, +			       GFP_KERNEL | __GFP_ZERO)) +		BUG();  	return 0;  } @@ -271,12 +341,16 @@ static int class_index(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct class_datum *cladatum; +	struct flex_array *fa;  	cladatum = datum;  	p = datap;  	if (!cladatum->value || cladatum->value > p->p_classes.nprim)  		return -EINVAL; -	p->p_class_val_to_name[cladatum->value - 1] = key; +	fa = p->sym_val_to_name[SYM_CLASSES]; +	if (flex_array_put_ptr(fa, cladatum->value - 1, key, +			       GFP_KERNEL | __GFP_ZERO)) +		BUG();  	p->class_val_to_struct[cladatum->value - 1] = cladatum;  	return 0;  } @@ -285,6 +359,7 @@ static int role_index(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct role_datum *role; +	struct flex_array *fa;  	role = datum;  	p = datap; @@ -292,7 +367,11 @@ static int role_index(void *key, void *datum, void *datap)  	    || role->value > p->p_roles.nprim  	    || role->bounds > p->p_roles.nprim)  		return -EINVAL; -	p->p_role_val_to_name[role->value - 1] = key; + +	fa = p->sym_val_to_name[SYM_ROLES]; +	if (flex_array_put_ptr(fa, role->value - 1, key, +			       GFP_KERNEL | __GFP_ZERO)) +		BUG();  	p->role_val_to_struct[role->value - 1] = role;  	return 0;  } @@ -301,6 +380,7 @@ static int type_index(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct type_datum *typdatum; +	struct flex_array *fa;  	typdatum = datum;  	p = datap; @@ -310,8 +390,15 @@ static int type_index(void *key, void *datum, void *datap)  		    || typdatum->value > p->p_types.nprim  		    || typdatum->bounds > p->p_types.nprim)  			return -EINVAL; -		p->p_type_val_to_name[typdatum->value - 1] = key; -		p->type_val_to_struct[typdatum->value - 1] = typdatum; +		fa = p->sym_val_to_name[SYM_TYPES]; +		if (flex_array_put_ptr(fa, typdatum->value - 1, key, +				       GFP_KERNEL | __GFP_ZERO)) +			BUG(); + +		fa = p->type_val_to_struct_array; +		if (flex_array_put_ptr(fa, typdatum->value - 1, typdatum, +				       GFP_KERNEL | __GFP_ZERO)) +			BUG();  	}  	return 0; @@ -321,6 +408,7 @@ static int user_index(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct user_datum *usrdatum; +	struct flex_array *fa;  	usrdatum = datum;  	p = datap; @@ -328,7 +416,11 @@ static int user_index(void *key, void *datum, void *datap)  	    || usrdatum->value > p->p_users.nprim  	    || usrdatum->bounds > p->p_users.nprim)  		return -EINVAL; -	p->p_user_val_to_name[usrdatum->value - 1] = key; + +	fa = p->sym_val_to_name[SYM_USERS]; +	if (flex_array_put_ptr(fa, usrdatum->value - 1, key, +			       GFP_KERNEL | __GFP_ZERO)) +		BUG();  	p->user_val_to_struct[usrdatum->value - 1] = usrdatum;  	return 0;  } @@ -337,6 +429,7 @@ static int sens_index(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct level_datum *levdatum; +	struct flex_array *fa;  	levdatum = datum;  	p = datap; @@ -345,7 +438,10 @@ static int sens_index(void *key, void *datum, void *datap)  		if (!levdatum->level->sens ||  		    levdatum->level->sens > p->p_levels.nprim)  			return -EINVAL; -		p->p_sens_val_to_name[levdatum->level->sens - 1] = key; +		fa = p->sym_val_to_name[SYM_LEVELS]; +		if (flex_array_put_ptr(fa, levdatum->level->sens - 1, key, +				       GFP_KERNEL | __GFP_ZERO)) +			BUG();  	}  	return 0; @@ -355,6 +451,7 @@ static int cat_index(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct cat_datum *catdatum; +	struct flex_array *fa;  	catdatum = datum;  	p = datap; @@ -362,7 +459,10 @@ static int cat_index(void *key, void *datum, void *datap)  	if (!catdatum->isalias) {  		if (!catdatum->value || catdatum->value > p->p_cats.nprim)  			return -EINVAL; -		p->p_cat_val_to_name[catdatum->value - 1] = key; +		fa = p->sym_val_to_name[SYM_CATS]; +		if (flex_array_put_ptr(fa, catdatum->value - 1, key, +				       GFP_KERNEL | __GFP_ZERO)) +			BUG();  	}  	return 0; @@ -380,74 +480,27 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =  	cat_index,  }; -/* - * Define the common val_to_name array and the class - * val_to_name and val_to_struct arrays in a policy - * database structure. - * - * Caller must clean up upon failure. - */ -static int policydb_index_classes(struct policydb *p) +#ifdef DEBUG_HASHES +static void hash_eval(struct hashtab *h, const char *hash_name)  { -	int rc; - -	p->p_common_val_to_name = -		kmalloc(p->p_commons.nprim * sizeof(char *), GFP_KERNEL); -	if (!p->p_common_val_to_name) { -		rc = -ENOMEM; -		goto out; -	} - -	rc = hashtab_map(p->p_commons.table, common_index, p); -	if (rc) -		goto out; - -	p->class_val_to_struct = -		kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), GFP_KERNEL); -	if (!p->class_val_to_struct) { -		rc = -ENOMEM; -		goto out; -	} - -	p->p_class_val_to_name = -		kmalloc(p->p_classes.nprim * sizeof(char *), GFP_KERNEL); -	if (!p->p_class_val_to_name) { -		rc = -ENOMEM; -		goto out; -	} +	struct hashtab_info info; -	rc = hashtab_map(p->p_classes.table, class_index, p); -out: -	return rc; +	hashtab_stat(h, &info); +	printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, " +	       "longest chain length %d\n", hash_name, h->nel, +	       info.slots_used, h->size, info.max_chain_len);  } -#ifdef DEBUG_HASHES  static void symtab_hash_eval(struct symtab *s)  {  	int i; -	for (i = 0; i < SYM_NUM; i++) { -		struct hashtab *h = s[i].table; -		struct hashtab_info info; - -		hashtab_stat(h, &info); -		printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, " -		       "longest chain length %d\n", symtab_name[i], h->nel, -		       info.slots_used, h->size, info.max_chain_len); -	} +	for (i = 0; i < SYM_NUM; i++) +		hash_eval(s[i].table, symtab_name[i]);  } -static void rangetr_hash_eval(struct hashtab *h) -{ -	struct hashtab_info info; - -	hashtab_stat(h, &info); -	printk(KERN_DEBUG "SELinux: rangetr:  %d entries and %d/%d buckets used, " -	       "longest chain length %d\n", h->nel, -	       info.slots_used, h->size, info.max_chain_len); -}  #else -static inline void rangetr_hash_eval(struct hashtab *h) +static inline void hash_eval(struct hashtab *h, char *hash_name)  {  }  #endif @@ -458,9 +511,9 @@ static inline void rangetr_hash_eval(struct hashtab *h)   *   * Caller must clean up on failure.   */ -static int policydb_index_others(struct policydb *p) +static int policydb_index(struct policydb *p)  { -	int i, rc = 0; +	int i, rc;  	printk(KERN_DEBUG "SELinux:  %d users, %d roles, %d types, %d bools",  	       p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); @@ -477,47 +530,63 @@ static int policydb_index_others(struct policydb *p)  	symtab_hash_eval(p->symtab);  #endif +	rc = -ENOMEM; +	p->class_val_to_struct = +		kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), +			GFP_KERNEL); +	if (!p->class_val_to_struct) +		goto out; + +	rc = -ENOMEM;  	p->role_val_to_struct =  		kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)),  			GFP_KERNEL); -	if (!p->role_val_to_struct) { -		rc = -ENOMEM; +	if (!p->role_val_to_struct)  		goto out; -	} +	rc = -ENOMEM;  	p->user_val_to_struct =  		kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)),  			GFP_KERNEL); -	if (!p->user_val_to_struct) { -		rc = -ENOMEM; +	if (!p->user_val_to_struct)  		goto out; -	} -	p->type_val_to_struct = -		kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)), -			GFP_KERNEL); -	if (!p->type_val_to_struct) { -		rc = -ENOMEM; +	/* Yes, I want the sizeof the pointer, not the structure */ +	rc = -ENOMEM; +	p->type_val_to_struct_array = flex_array_alloc(sizeof(struct type_datum *), +						       p->p_types.nprim, +						       GFP_KERNEL | __GFP_ZERO); +	if (!p->type_val_to_struct_array)  		goto out; -	} -	if (cond_init_bool_indexes(p)) { -		rc = -ENOMEM; +	rc = flex_array_prealloc(p->type_val_to_struct_array, 0, +				 p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); +	if (rc)  		goto out; -	} -	for (i = SYM_ROLES; i < SYM_NUM; i++) { -		p->sym_val_to_name[i] = -			kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL); -		if (!p->sym_val_to_name[i]) { -			rc = -ENOMEM; +	rc = cond_init_bool_indexes(p); +	if (rc) +		goto out; + +	for (i = 0; i < SYM_NUM; i++) { +		rc = -ENOMEM; +		p->sym_val_to_name[i] = flex_array_alloc(sizeof(char *), +							 p->symtab[i].nprim, +							 GFP_KERNEL | __GFP_ZERO); +		if (!p->sym_val_to_name[i])  			goto out; -		} + +		rc = flex_array_prealloc(p->sym_val_to_name[i], +					 0, p->symtab[i].nprim, +					 GFP_KERNEL | __GFP_ZERO); +		if (rc) +			goto out; +  		rc = hashtab_map(p->symtab[i].table, index_f[i], p);  		if (rc)  			goto out;  	} - +	rc = 0;  out:  	return rc;  } @@ -540,13 +609,28 @@ static int common_destroy(void *key, void *datum, void *p)  	struct common_datum *comdatum;  	kfree(key); -	comdatum = datum; -	hashtab_map(comdatum->permissions.table, perm_destroy, NULL); -	hashtab_destroy(comdatum->permissions.table); +	if (datum) { +		comdatum = datum; +		hashtab_map(comdatum->permissions.table, perm_destroy, NULL); +		hashtab_destroy(comdatum->permissions.table); +	}  	kfree(datum);  	return 0;  } +static void constraint_expr_destroy(struct constraint_expr *expr) +{ +	if (expr) { +		ebitmap_destroy(&expr->names); +		if (expr->type_names) { +			ebitmap_destroy(&expr->type_names->types); +			ebitmap_destroy(&expr->type_names->negset); +			kfree(expr->type_names); +		} +		kfree(expr); +	} +} +  static int cls_destroy(void *key, void *datum, void *p)  {  	struct class_datum *cladatum; @@ -554,38 +638,37 @@ static int cls_destroy(void *key, void *datum, void *p)  	struct constraint_expr *e, *etmp;  	kfree(key); -	cladatum = datum; -	hashtab_map(cladatum->permissions.table, perm_destroy, NULL); -	hashtab_destroy(cladatum->permissions.table); -	constraint = cladatum->constraints; -	while (constraint) { -		e = constraint->expr; -		while (e) { -			ebitmap_destroy(&e->names); -			etmp = e; -			e = e->next; -			kfree(etmp); +	if (datum) { +		cladatum = datum; +		hashtab_map(cladatum->permissions.table, perm_destroy, NULL); +		hashtab_destroy(cladatum->permissions.table); +		constraint = cladatum->constraints; +		while (constraint) { +			e = constraint->expr; +			while (e) { +				etmp = e; +				e = e->next; +				constraint_expr_destroy(etmp); +			} +			ctemp = constraint; +			constraint = constraint->next; +			kfree(ctemp);  		} -		ctemp = constraint; -		constraint = constraint->next; -		kfree(ctemp); -	} - -	constraint = cladatum->validatetrans; -	while (constraint) { -		e = constraint->expr; -		while (e) { -			ebitmap_destroy(&e->names); -			etmp = e; -			e = e->next; -			kfree(etmp); + +		constraint = cladatum->validatetrans; +		while (constraint) { +			e = constraint->expr; +			while (e) { +				etmp = e; +				e = e->next; +				constraint_expr_destroy(etmp); +			} +			ctemp = constraint; +			constraint = constraint->next; +			kfree(ctemp);  		} -		ctemp = constraint; -		constraint = constraint->next; -		kfree(ctemp); +		kfree(cladatum->comkey);  	} - -	kfree(cladatum->comkey);  	kfree(datum);  	return 0;  } @@ -595,9 +678,11 @@ static int role_destroy(void *key, void *datum, void *p)  	struct role_datum *role;  	kfree(key); -	role = datum; -	ebitmap_destroy(&role->dominates); -	ebitmap_destroy(&role->types); +	if (datum) { +		role = datum; +		ebitmap_destroy(&role->dominates); +		ebitmap_destroy(&role->types); +	}  	kfree(datum);  	return 0;  } @@ -614,11 +699,13 @@ static int user_destroy(void *key, void *datum, void *p)  	struct user_datum *usrdatum;  	kfree(key); -	usrdatum = datum; -	ebitmap_destroy(&usrdatum->roles); -	ebitmap_destroy(&usrdatum->range.level[0].cat); -	ebitmap_destroy(&usrdatum->range.level[1].cat); -	ebitmap_destroy(&usrdatum->dfltlevel.cat); +	if (datum) { +		usrdatum = datum; +		ebitmap_destroy(&usrdatum->roles); +		ebitmap_destroy(&usrdatum->range.level[0].cat); +		ebitmap_destroy(&usrdatum->range.level[1].cat); +		ebitmap_destroy(&usrdatum->dfltlevel.cat); +	}  	kfree(datum);  	return 0;  } @@ -628,9 +715,11 @@ static int sens_destroy(void *key, void *datum, void *p)  	struct level_datum *levdatum;  	kfree(key); -	levdatum = datum; -	ebitmap_destroy(&levdatum->level->cat); -	kfree(levdatum->level); +	if (datum) { +		levdatum = datum; +		ebitmap_destroy(&levdatum->level->cat); +		kfree(levdatum->level); +	}  	kfree(datum);  	return 0;  } @@ -654,6 +743,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =  	cat_destroy,  }; +static int filenametr_destroy(void *key, void *datum, void *p) +{ +	struct filename_trans *ft = key; +	kfree(ft->name); +	kfree(key); +	kfree(datum); +	cond_resched(); +	return 0; +} +  static int range_tr_destroy(void *key, void *datum, void *p)  {  	struct mls_range *rt = datum; @@ -695,13 +794,16 @@ void policydb_destroy(struct policydb *p)  		hashtab_destroy(p->symtab[i].table);  	} -	for (i = 0; i < SYM_NUM; i++) -		kfree(p->sym_val_to_name[i]); +	for (i = 0; i < SYM_NUM; i++) { +		if (p->sym_val_to_name[i]) +			flex_array_free(p->sym_val_to_name[i]); +	}  	kfree(p->class_val_to_struct);  	kfree(p->role_val_to_struct);  	kfree(p->user_val_to_struct); -	kfree(p->type_val_to_struct); +	if (p->type_val_to_struct_array) +		flex_array_free(p->type_val_to_struct_array);  	avtab_destroy(&p->te_avtab); @@ -748,6 +850,9 @@ void policydb_destroy(struct policydb *p)  	}  	kfree(lra); +	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); @@ -762,6 +867,8 @@ void policydb_destroy(struct policydb *p)  		}  		flex_array_free(p->type_attr_map_array);  	} + +	ebitmap_destroy(&p->filename_trans_ttypes);  	ebitmap_destroy(&p->policycaps);  	ebitmap_destroy(&p->permissive_map); @@ -785,19 +892,21 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)  	head = p->ocontexts[OCON_ISID];  	for (c = head; c; c = c->next) { +		rc = -EINVAL;  		if (!c->context[0].user) { -			printk(KERN_ERR "SELinux:  SID %s was never " -			       "defined.\n", c->u.name); -			rc = -EINVAL; +			printk(KERN_ERR "SELinux:  SID %s was never defined.\n", +				c->u.name);  			goto out;  		} -		if (sidtab_insert(s, c->sid[0], &c->context[0])) { -			printk(KERN_ERR "SELinux:  unable to load initial " -			       "SID %s.\n", c->u.name); -			rc = -EINVAL; + +		rc = sidtab_insert(s, c->sid[0], &c->context[0]); +		if (rc) { +			printk(KERN_ERR "SELinux:  unable to load initial SID %s.\n", +				c->u.name);  			goto out;  		}  	} +	rc = 0;  out:  	return rc;  } @@ -846,8 +955,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)  		 * Role must be authorized for the type.  		 */  		role = p->role_val_to_struct[c->role - 1]; -		if (!ebitmap_get_bit(&role->types, -				     c->type - 1)) +		if (!ebitmap_get_bit(&role->types, c->type - 1))  			/* role may not be associated with type */  			return 0; @@ -858,8 +966,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)  		if (!usrdatum)  			return 0; -		if (!ebitmap_get_bit(&usrdatum->roles, -				     c->role - 1)) +		if (!ebitmap_get_bit(&usrdatum->roles, c->role - 1))  			/* user may not be associated with role */  			return 0;  	} @@ -881,20 +988,22 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)  	int rc;  	rc = next_entry(buf, fp, sizeof(u32)); -	if (rc < 0) +	if (rc)  		goto out; +	rc = -EINVAL;  	items = le32_to_cpu(buf[0]);  	if (items > ARRAY_SIZE(buf)) {  		printk(KERN_ERR "SELinux: mls:  range overflow\n"); -		rc = -EINVAL;  		goto out;  	} +  	rc = next_entry(buf, fp, sizeof(u32) * items); -	if (rc < 0) { +	if (rc) {  		printk(KERN_ERR "SELinux: mls:  truncated range\n");  		goto out;  	} +  	r->level[0].sens = le32_to_cpu(buf[0]);  	if (items > 1)  		r->level[1].sens = le32_to_cpu(buf[1]); @@ -903,15 +1012,13 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)  	rc = ebitmap_read(&r->level[0].cat, fp);  	if (rc) { -		printk(KERN_ERR "SELinux: mls:  error reading low " -		       "categories\n"); +		printk(KERN_ERR "SELinux: mls:  error reading low categories\n");  		goto out;  	}  	if (items > 1) {  		rc = ebitmap_read(&r->level[1].cat, fp);  		if (rc) { -			printk(KERN_ERR "SELinux: mls:  error reading high " -			       "categories\n"); +			printk(KERN_ERR "SELinux: mls:  error reading high categories\n");  			goto bad_high;  		}  	} else { @@ -922,12 +1029,11 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)  		}  	} -	rc = 0; -out: -	return rc; +	return 0;  bad_high:  	ebitmap_destroy(&r->level[0].cat); -	goto out; +out: +	return rc;  }  /* @@ -942,7 +1048,7 @@ static int context_read_and_validate(struct context *c,  	int rc;  	rc = next_entry(buf, fp, sizeof buf); -	if (rc < 0) { +	if (rc) {  		printk(KERN_ERR "SELinux: context truncated\n");  		goto out;  	} @@ -950,19 +1056,20 @@ static int context_read_and_validate(struct context *c,  	c->role = le32_to_cpu(buf[1]);  	c->type = le32_to_cpu(buf[2]);  	if (p->policyvers >= POLICYDB_VERSION_MLS) { -		if (mls_read_range_helper(&c->range, fp)) { -			printk(KERN_ERR "SELinux: error reading MLS range of " -			       "context\n"); -			rc = -EINVAL; +		rc = mls_read_range_helper(&c->range, fp); +		if (rc) { +			printk(KERN_ERR "SELinux: error reading MLS range of context\n");  			goto out;  		}  	} +	rc = -EINVAL;  	if (!policydb_context_isvalid(p, c)) {  		printk(KERN_ERR "SELinux:  invalid security context\n");  		context_destroy(c); -		rc = -EINVAL; +		goto out;  	} +	rc = 0;  out:  	return rc;  } @@ -981,37 +1088,36 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp)  	__le32 buf[2];  	u32 len; +	rc = -ENOMEM;  	perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL); -	if (!perdatum) { -		rc = -ENOMEM; -		goto out; -	} +	if (!perdatum) +		goto bad;  	rc = next_entry(buf, fp, sizeof buf); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]);  	perdatum->value = le32_to_cpu(buf[1]); +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_KERNEL); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	} +  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0';  	rc = hashtab_insert(h, key, perdatum);  	if (rc)  		goto bad; -out: -	return rc; + +	return 0;  bad:  	perm_destroy(key, perdatum, NULL); -	goto out; +	return rc;  }  static int common_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1022,14 +1128,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)  	u32 len, nel;  	int i, rc; +	rc = -ENOMEM;  	comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL); -	if (!comdatum) { -		rc = -ENOMEM; -		goto out; -	} +	if (!comdatum) +		goto bad;  	rc = next_entry(buf, fp, sizeof buf); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]); @@ -1041,13 +1146,13 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)  	comdatum->permissions.nprim = le32_to_cpu(buf[2]);  	nel = le32_to_cpu(buf[3]); +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_KERNEL); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	} +  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0'; @@ -1060,15 +1165,40 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)  	rc = hashtab_insert(h, key, comdatum);  	if (rc)  		goto bad; -out: -	return rc; +	return 0;  bad:  	common_destroy(key, comdatum, NULL); -	goto out; +	return rc;  } -static int read_cons_helper(struct constraint_node **nodep, int ncons, -			    int allowxtarget, void *fp) +static void type_set_init(struct type_set *t) +{ +	ebitmap_init(&t->types); +	ebitmap_init(&t->negset); +} + +static int type_set_read(struct type_set *t, void *fp) +{ +	__le32 buf[1]; +	int rc; + +	if (ebitmap_read(&t->types, fp)) +		return -EINVAL; +	if (ebitmap_read(&t->negset, fp)) +		return -EINVAL; + +	rc = next_entry(buf, fp, sizeof(u32)); +	if (rc < 0) +		return -EINVAL; +	t->flags = le32_to_cpu(buf[0]); + +	return 0; +} + + +static int read_cons_helper(struct policydb *p, +				struct constraint_node **nodep, +				int ncons, int allowxtarget, void *fp)  {  	struct constraint_node *c, *lc;  	struct constraint_expr *e, *le; @@ -1088,7 +1218,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,  			*nodep = c;  		rc = next_entry(buf, fp, (sizeof(u32) * 2)); -		if (rc < 0) +		if (rc)  			return rc;  		c->permissions = le32_to_cpu(buf[0]);  		nexpr = le32_to_cpu(buf[1]); @@ -1105,7 +1235,7 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,  				c->expr = e;  			rc = next_entry(buf, fp, (sizeof(u32) * 3)); -			if (rc < 0) +			if (rc)  				return rc;  			e->expr_type = le32_to_cpu(buf[0]);  			e->attr = le32_to_cpu(buf[1]); @@ -1133,8 +1263,21 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,  				if (depth == (CEXPR_MAXDEPTH - 1))  					return -EINVAL;  				depth++; -				if (ebitmap_read(&e->names, fp)) -					return -EINVAL; +				rc = ebitmap_read(&e->names, fp); +				if (rc) +					return rc; +				if (p->policyvers >= +					POLICYDB_VERSION_CONSTRAINT_NAMES) { +						e->type_names = kzalloc(sizeof +						(*e->type_names), +						GFP_KERNEL); +					if (!e->type_names) +						return -ENOMEM; +					type_set_init(e->type_names); +					rc = type_set_read(e->type_names, fp); +					if (rc) +						return rc; +				}  				break;  			default:  				return -EINVAL; @@ -1157,14 +1300,13 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)  	u32 len, len2, ncons, nel;  	int i, rc; +	rc = -ENOMEM;  	cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL); -	if (!cladatum) { -		rc = -ENOMEM; -		goto out; -	} +	if (!cladatum) +		goto bad;  	rc = next_entry(buf, fp, sizeof(u32)*6); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]); @@ -1179,33 +1321,30 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)  	ncons = le32_to_cpu(buf[5]); +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_KERNEL); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	} +  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0';  	if (len2) { +		rc = -ENOMEM;  		cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); -		if (!cladatum->comkey) { -			rc = -ENOMEM; +		if (!cladatum->comkey)  			goto bad; -		}  		rc = next_entry(cladatum->comkey, fp, len2); -		if (rc < 0) +		if (rc)  			goto bad;  		cladatum->comkey[len2] = '\0'; -		cladatum->comdatum = hashtab_search(p->p_commons.table, -						    cladatum->comkey); +		rc = -EINVAL; +		cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey);  		if (!cladatum->comdatum) { -			printk(KERN_ERR "SELinux:  unknown common %s\n", -			       cladatum->comkey); -			rc = -EINVAL; +			printk(KERN_ERR "SELinux:  unknown common %s\n", cladatum->comkey);  			goto bad;  		}  	} @@ -1215,31 +1354,47 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)  			goto bad;  	} -	rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); +	rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);  	if (rc)  		goto bad;  	if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {  		/* grab the validatetrans rules */  		rc = next_entry(buf, fp, sizeof(u32)); -		if (rc < 0) +		if (rc)  			goto bad;  		ncons = le32_to_cpu(buf[0]); -		rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); +		rc = read_cons_helper(p, &cladatum->validatetrans, +				ncons, 1, fp); +		if (rc) +			goto bad; +	} + +	if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { +		rc = next_entry(buf, fp, sizeof(u32) * 3);  		if (rc)  			goto bad; + +		cladatum->default_user = le32_to_cpu(buf[0]); +		cladatum->default_role = le32_to_cpu(buf[1]); +		cladatum->default_range = le32_to_cpu(buf[2]); +	} + +	if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { +		rc = next_entry(buf, fp, sizeof(u32) * 1); +		if (rc) +			goto bad; +		cladatum->default_type = le32_to_cpu(buf[0]);  	}  	rc = hashtab_insert(h, key, cladatum);  	if (rc)  		goto bad; -	rc = 0; -out: -	return rc; +	return 0;  bad:  	cls_destroy(key, cladatum, NULL); -	goto out; +	return rc;  }  static int role_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1250,17 +1405,16 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)  	__le32 buf[3];  	u32 len; +	rc = -ENOMEM;  	role = kzalloc(sizeof(*role), GFP_KERNEL); -	if (!role) { -		rc = -ENOMEM; -		goto out; -	} +	if (!role) +		goto bad;  	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)  		to_read = 3;  	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]); @@ -1268,13 +1422,13 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)  	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)  		role->bounds = le32_to_cpu(buf[2]); +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_KERNEL); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	} +  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0'; @@ -1287,10 +1441,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)  		goto bad;  	if (strcmp(key, OBJECT_R) == 0) { +		rc = -EINVAL;  		if (role->value != OBJECT_R_VAL) {  			printk(KERN_ERR "SELinux: Role %s has wrong value %d\n",  			       OBJECT_R, role->value); -			rc = -EINVAL;  			goto bad;  		}  		rc = 0; @@ -1300,11 +1454,10 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)  	rc = hashtab_insert(h, key, role);  	if (rc)  		goto bad; -out: -	return rc; +	return 0;  bad:  	role_destroy(key, role, NULL); -	goto out; +	return rc;  }  static int type_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1315,17 +1468,16 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)  	__le32 buf[4];  	u32 len; +	rc = -ENOMEM;  	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); -	if (!typdatum) { -		rc = -ENOMEM; -		return rc; -	} +	if (!typdatum) +		goto bad;  	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)  		to_read = 4;  	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]); @@ -1343,24 +1495,22 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)  		typdatum->primary = le32_to_cpu(buf[2]);  	} +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_KERNEL); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	}  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0';  	rc = hashtab_insert(h, key, typdatum);  	if (rc)  		goto bad; -out: -	return rc; +	return 0;  bad:  	type_destroy(key, typdatum, NULL); -	goto out; +	return rc;  } @@ -1376,22 +1526,18 @@ static int mls_read_level(struct mls_level *lp, void *fp)  	memset(lp, 0, sizeof(*lp));  	rc = next_entry(buf, fp, sizeof buf); -	if (rc < 0) { +	if (rc) {  		printk(KERN_ERR "SELinux: mls: truncated level\n"); -		goto bad; +		return rc;  	}  	lp->sens = le32_to_cpu(buf[0]); -	if (ebitmap_read(&lp->cat, fp)) { -		printk(KERN_ERR "SELinux: mls:  error reading level " -		       "categories\n"); -		goto bad; +	rc = ebitmap_read(&lp->cat, fp); +	if (rc) { +		printk(KERN_ERR "SELinux: mls:  error reading level categories\n"); +		return rc;  	} -  	return 0; - -bad: -	return -EINVAL;  }  static int user_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1402,17 +1548,16 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)  	__le32 buf[3];  	u32 len; +	rc = -ENOMEM;  	usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); -	if (!usrdatum) { -		rc = -ENOMEM; -		goto out; -	} +	if (!usrdatum) +		goto bad;  	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)  		to_read = 3;  	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]); @@ -1420,13 +1565,12 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)  	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)  		usrdatum->bounds = le32_to_cpu(buf[2]); +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_KERNEL); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	}  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0'; @@ -1446,11 +1590,10 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)  	rc = hashtab_insert(h, key, usrdatum);  	if (rc)  		goto bad; -out: -	return rc; +	return 0;  bad:  	user_destroy(key, usrdatum, NULL); -	goto out; +	return rc;  }  static int sens_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1461,47 +1604,43 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp)  	__le32 buf[2];  	u32 len; +	rc = -ENOMEM;  	levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC); -	if (!levdatum) { -		rc = -ENOMEM; -		goto out; -	} +	if (!levdatum) +		goto bad;  	rc = next_entry(buf, fp, sizeof buf); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]);  	levdatum->isalias = le32_to_cpu(buf[1]); +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_ATOMIC); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	}  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0'; +	rc = -ENOMEM;  	levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); -	if (!levdatum->level) { -		rc = -ENOMEM; +	if (!levdatum->level)  		goto bad; -	} -	if (mls_read_level(levdatum->level, fp)) { -		rc = -EINVAL; + +	rc = mls_read_level(levdatum->level, fp); +	if (rc)  		goto bad; -	}  	rc = hashtab_insert(h, key, levdatum);  	if (rc)  		goto bad; -out: -	return rc; +	return 0;  bad:  	sens_destroy(key, levdatum, NULL); -	goto out; +	return rc;  }  static int cat_read(struct policydb *p, struct hashtab *h, void *fp) @@ -1512,39 +1651,35 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp)  	__le32 buf[3];  	u32 len; +	rc = -ENOMEM;  	catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC); -	if (!catdatum) { -		rc = -ENOMEM; -		goto out; -	} +	if (!catdatum) +		goto bad;  	rc = next_entry(buf, fp, sizeof buf); -	if (rc < 0) +	if (rc)  		goto bad;  	len = le32_to_cpu(buf[0]);  	catdatum->value = le32_to_cpu(buf[1]);  	catdatum->isalias = le32_to_cpu(buf[2]); +	rc = -ENOMEM;  	key = kmalloc(len + 1, GFP_ATOMIC); -	if (!key) { -		rc = -ENOMEM; +	if (!key)  		goto bad; -	}  	rc = next_entry(key, fp, len); -	if (rc < 0) +	if (rc)  		goto bad;  	key[len] = '\0';  	rc = hashtab_insert(h, key, catdatum);  	if (rc)  		goto bad; -out: -	return rc; - +	return 0;  bad:  	cat_destroy(key, catdatum, NULL); -	goto out; +	return rc;  }  static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) = @@ -1585,9 +1720,9 @@ static int user_bounds_sanity_check(void *key, void *datum, void *datap)  			printk(KERN_ERR  			       "SELinux: boundary violated policy: "  			       "user=%s role=%s bounds=%s\n", -			       p->p_user_val_to_name[user->value - 1], -			       p->p_role_val_to_name[bit], -			       p->p_user_val_to_name[upper->value - 1]); +			       sym_name(p, SYM_USERS, user->value - 1), +			       sym_name(p, SYM_ROLES, bit), +			       sym_name(p, SYM_USERS, upper->value - 1));  			return -EINVAL;  		} @@ -1622,9 +1757,9 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap)  			printk(KERN_ERR  			       "SELinux: boundary violated policy: "  			       "role=%s type=%s bounds=%s\n", -			       p->p_role_val_to_name[role->value - 1], -			       p->p_type_val_to_name[bit], -			       p->p_role_val_to_name[upper->value - 1]); +			       sym_name(p, SYM_ROLES, role->value - 1), +			       sym_name(p, SYM_TYPES, bit), +			       sym_name(p, SYM_ROLES, upper->value - 1));  			return -EINVAL;  		} @@ -1648,12 +1783,15 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)  			return -EINVAL;  		} -		upper = p->type_val_to_struct[upper->bounds - 1]; +		upper = flex_array_get_ptr(p->type_val_to_struct_array, +					   upper->bounds - 1); +		BUG_ON(!upper); +  		if (upper->attribute) {  			printk(KERN_ERR "SELinux: type %s: "  			       "bounded by attribute %s",  			       (char *) key, -			       p->p_type_val_to_name[upper->value - 1]); +			       sym_name(p, SYM_TYPES, upper->value - 1));  			return -EINVAL;  		}  	} @@ -1686,8 +1824,6 @@ static int policydb_bounds_sanity_check(struct policydb *p)  	return 0;  } -extern int ss_initialized; -  u16 string_to_security_class(struct policydb *p, const char *name)  {  	struct class_datum *cladatum; @@ -1786,7 +1922,7 @@ static int range_read(struct policydb *p, void *fp)  		rt = NULL;  		r = NULL;  	} -	rangetr_hash_eval(p->range_tr); +	hash_eval(p->range_tr, "rangetr");  	rc = 0;  out:  	kfree(rt); @@ -1794,6 +1930,95 @@ out:  	return rc;  } +static int filename_trans_read(struct policydb *p, void *fp) +{ +	struct filename_trans *ft; +	struct filename_trans_datum *otype; +	char *name; +	u32 nel, len; +	__le32 buf[4]; +	int rc, i; + +	if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) +		return 0; + +	rc = next_entry(buf, fp, sizeof(u32)); +	if (rc) +		return rc; +	nel = le32_to_cpu(buf[0]); + +	for (i = 0; i < nel; i++) { +		ft = NULL; +		otype = NULL; +		name = NULL; + +		rc = -ENOMEM; +		ft = kzalloc(sizeof(*ft), GFP_KERNEL); +		if (!ft) +			goto out; + +		rc = -ENOMEM; +		otype = kmalloc(sizeof(*otype), GFP_KERNEL); +		if (!otype) +			goto out; + +		/* length of the path component string */ +		rc = next_entry(buf, fp, sizeof(u32)); +		if (rc) +			goto out; +		len = le32_to_cpu(buf[0]); + +		rc = -ENOMEM; +		name = kmalloc(len + 1, GFP_KERNEL); +		if (!name) +			goto out; + +		ft->name = name; + +		/* path component string */ +		rc = next_entry(name, fp, len); +		if (rc) +			goto out; +		name[len] = 0; + +		rc = next_entry(buf, fp, sizeof(u32) * 4); +		if (rc) +			goto out; + +		ft->stype = le32_to_cpu(buf[0]); +		ft->ttype = le32_to_cpu(buf[1]); +		ft->tclass = le32_to_cpu(buf[2]); + +		otype->otype = le32_to_cpu(buf[3]); + +		rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1); +		if (rc) +			goto out; + +		rc = hashtab_insert(p->filename_trans, ft, otype); +		if (rc) { +			/* +			 * Do not return -EEXIST to the caller, or the system +			 * will not boot. +			 */ +			if (rc != -EEXIST) +				goto out; +			/* But free memory to avoid memory leak. */ +			kfree(ft); +			kfree(name); +			kfree(otype); +		} +	} +	hash_eval(p->filename_trans, "filenametr"); +	return 0; +out: +	kfree(ft); +	kfree(name); +	kfree(otype); + +	return rc; +} +  static int genfs_read(struct policydb *p, void *fp)  {  	int i, j, rc; @@ -2009,7 +2234,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,  				rc = -EINVAL;  				c->v.behavior = le32_to_cpu(buf[0]); -				if (c->v.behavior > SECURITY_FS_USE_NONE) +				/* Determined at runtime, not in policy DB. */ +				if (c->v.behavior == SECURITY_FS_USE_MNTPOINT) +					goto out; +				if (c->v.behavior > SECURITY_FS_USE_MAX)  					goto out;  				rc = -ENOMEM; @@ -2066,13 +2294,14 @@ int policydb_read(struct policydb *p, void *fp)  	rc = policydb_init(p);  	if (rc) -		goto out; +		return rc;  	/* Read the magic number and string length. */  	rc = next_entry(buf, fp, sizeof(u32) * 2); -	if (rc < 0) +	if (rc)  		goto bad; +	rc = -EINVAL;  	if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {  		printk(KERN_ERR "SELinux:  policydb magic number 0x%x does "  		       "not match expected magic number 0x%x\n", @@ -2080,6 +2309,7 @@ int policydb_read(struct policydb *p, void *fp)  		goto bad;  	} +	rc = -EINVAL;  	len = le32_to_cpu(buf[1]);  	if (len != strlen(POLICYDB_STRING)) {  		printk(KERN_ERR "SELinux:  policydb string length %d does not " @@ -2087,19 +2317,23 @@ int policydb_read(struct policydb *p, void *fp)  		       len, strlen(POLICYDB_STRING));  		goto bad;  	} + +	rc = -ENOMEM;  	policydb_str = kmalloc(len + 1, GFP_KERNEL);  	if (!policydb_str) {  		printk(KERN_ERR "SELinux:  unable to allocate memory for policydb "  		       "string of length %d\n", len); -		rc = -ENOMEM;  		goto bad;  	} +  	rc = next_entry(policydb_str, fp, len); -	if (rc < 0) { +	if (rc) {  		printk(KERN_ERR "SELinux:  truncated policydb string identifier\n");  		kfree(policydb_str);  		goto bad;  	} + +	rc = -EINVAL;  	policydb_str[len] = '\0';  	if (strcmp(policydb_str, POLICYDB_STRING)) {  		printk(KERN_ERR "SELinux:  policydb string %s does not match " @@ -2113,9 +2347,10 @@ int policydb_read(struct policydb *p, void *fp)  	/* Read the version and table sizes. */  	rc = next_entry(buf, fp, sizeof(u32)*4); -	if (rc < 0) +	if (rc)  		goto bad; +	rc = -EINVAL;  	p->policyvers = le32_to_cpu(buf[0]);  	if (p->policyvers < POLICYDB_VERSION_MIN ||  	    p->policyvers > POLICYDB_VERSION_MAX) { @@ -2128,6 +2363,7 @@ int policydb_read(struct policydb *p, void *fp)  	if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {  		p->mls_enabled = 1; +		rc = -EINVAL;  		if (p->policyvers < POLICYDB_VERSION_MLS) {  			printk(KERN_ERR "SELinux: security policydb version %d "  				"(MLS) not backwards compatible\n", @@ -2138,14 +2374,19 @@ int policydb_read(struct policydb *p, void *fp)  	p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);  	p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); -	if (p->policyvers >= POLICYDB_VERSION_POLCAP && -	    ebitmap_read(&p->policycaps, fp) != 0) -		goto bad; +	if (p->policyvers >= POLICYDB_VERSION_POLCAP) { +		rc = ebitmap_read(&p->policycaps, fp); +		if (rc) +			goto bad; +	} -	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE && -	    ebitmap_read(&p->permissive_map, fp) != 0) -		goto bad; +	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) { +		rc = ebitmap_read(&p->permissive_map, fp); +		if (rc) +			goto bad; +	} +	rc = -EINVAL;  	info = policydb_lookup_compat(p->policyvers);  	if (!info) {  		printk(KERN_ERR "SELinux:  unable to find policy compat info " @@ -2153,6 +2394,7 @@ int policydb_read(struct policydb *p, void *fp)  		goto bad;  	} +	rc = -EINVAL;  	if (le32_to_cpu(buf[2]) != info->sym_num ||  		le32_to_cpu(buf[3]) != info->ocon_num) {  		printk(KERN_ERR "SELinux:  policydb table sizes (%d,%d) do " @@ -2164,7 +2406,7 @@ int policydb_read(struct policydb *p, void *fp)  	for (i = 0; i < info->sym_num; i++) {  		rc = next_entry(buf, fp, sizeof(u32)*2); -		if (rc < 0) +		if (rc)  			goto bad;  		nprim = le32_to_cpu(buf[0]);  		nel = le32_to_cpu(buf[1]); @@ -2177,6 +2419,11 @@ int policydb_read(struct policydb *p, void *fp)  		p->symtab[i].nprim = nprim;  	} +	rc = -EINVAL; +	p->process_class = string_to_security_class(p, "process"); +	if (!p->process_class) +		goto bad; +  	rc = avtab_read(&p->te_avtab, fp, p);  	if (rc)  		goto bad; @@ -2188,78 +2435,81 @@ int policydb_read(struct policydb *p, void *fp)  	}  	rc = next_entry(buf, fp, sizeof(u32)); -	if (rc < 0) +	if (rc)  		goto bad;  	nel = le32_to_cpu(buf[0]);  	ltr = NULL;  	for (i = 0; i < nel; i++) { +		rc = -ENOMEM;  		tr = kzalloc(sizeof(*tr), GFP_KERNEL); -		if (!tr) { -			rc = -ENOMEM; +		if (!tr)  			goto bad; -		}  		if (ltr)  			ltr->next = tr;  		else  			p->role_tr = tr;  		rc = next_entry(buf, fp, sizeof(u32)*3); -		if (rc < 0) +		if (rc)  			goto bad; + +		rc = -EINVAL;  		tr->role = le32_to_cpu(buf[0]);  		tr->type = le32_to_cpu(buf[1]);  		tr->new_role = le32_to_cpu(buf[2]); +		if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { +			rc = next_entry(buf, fp, sizeof(u32)); +			if (rc) +				goto bad; +			tr->tclass = le32_to_cpu(buf[0]); +		} else +			tr->tclass = p->process_class; +  		if (!policydb_role_isvalid(p, tr->role) ||  		    !policydb_type_isvalid(p, tr->type) || -		    !policydb_role_isvalid(p, tr->new_role)) { -			rc = -EINVAL; +		    !policydb_class_isvalid(p, tr->tclass) || +		    !policydb_role_isvalid(p, tr->new_role))  			goto bad; -		}  		ltr = tr;  	}  	rc = next_entry(buf, fp, sizeof(u32)); -	if (rc < 0) +	if (rc)  		goto bad;  	nel = le32_to_cpu(buf[0]);  	lra = NULL;  	for (i = 0; i < nel; i++) { +		rc = -ENOMEM;  		ra = kzalloc(sizeof(*ra), GFP_KERNEL); -		if (!ra) { -			rc = -ENOMEM; +		if (!ra)  			goto bad; -		}  		if (lra)  			lra->next = ra;  		else  			p->role_allow = ra;  		rc = next_entry(buf, fp, sizeof(u32)*2); -		if (rc < 0) +		if (rc)  			goto bad; + +		rc = -EINVAL;  		ra->role = le32_to_cpu(buf[0]);  		ra->new_role = le32_to_cpu(buf[1]);  		if (!policydb_role_isvalid(p, ra->role) || -		    !policydb_role_isvalid(p, ra->new_role)) { -			rc = -EINVAL; +		    !policydb_role_isvalid(p, ra->new_role))  			goto bad; -		}  		lra = ra;  	} -	rc = policydb_index_classes(p); +	rc = filename_trans_read(p, fp);  	if (rc)  		goto bad; -	rc = policydb_index_others(p); +	rc = policydb_index(p);  	if (rc)  		goto bad; -	p->process_class = string_to_security_class(p, "process"); -	if (!p->process_class) -		goto bad; -	p->process_trans_perms = string_to_av_perm(p, p->process_class, -						   "transition"); -	p->process_trans_perms |= string_to_av_perm(p, p->process_class, -						    "dyntransition"); +	rc = -EINVAL; +	p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); +	p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");  	if (!p->process_trans_perms)  		goto bad; @@ -2283,7 +2533,7 @@ int policydb_read(struct policydb *p, void *fp)  		goto bad;  	/* preallocate so we don't have to worry about the put ever failing */ -	rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1, +	rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim,  				 GFP_KERNEL | __GFP_ZERO);  	if (rc)  		goto bad; @@ -2312,8 +2562,6 @@ int policydb_read(struct policydb *p, void *fp)  out:  	return rc;  bad: -	if (!rc) -		rc = -EINVAL;  	policydb_destroy(p);  	goto out;  } @@ -2431,8 +2679,9 @@ static int cat_write(void *vkey, void *datum, void *ptr)  	return 0;  } -static int role_trans_write(struct role_trans *r, void *fp) +static int role_trans_write(struct policydb *p, void *fp)  { +	struct role_trans *r = p->role_tr;  	struct role_trans *tr;  	u32 buf[3];  	size_t nel; @@ -2452,6 +2701,12 @@ static int role_trans_write(struct role_trans *r, void *fp)  		rc = put_entry(buf, sizeof(u32), 3, fp);  		if (rc)  			return rc; +		if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { +			buf[0] = cpu_to_le32(tr->tclass); +			rc = put_entry(buf, sizeof(u32), 1, fp); +			if (rc) +				return rc; +		}  	}  	return 0; @@ -2564,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr)  	return 0;  } +static int type_set_write(struct type_set *t, void *fp) +{ +	int rc; +	__le32 buf[1]; + +	if (ebitmap_write(&t->types, fp)) +		return -EINVAL; +	if (ebitmap_write(&t->negset, fp)) +		return -EINVAL; + +	buf[0] = cpu_to_le32(t->flags); +	rc = put_entry(buf, sizeof(u32), 1, fp); +	if (rc) +		return -EINVAL; + +	return 0; +} +  static int write_cons_helper(struct policydb *p, struct constraint_node *node,  			     void *fp)  { @@ -2595,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,  				rc = ebitmap_write(&e->names, fp);  				if (rc)  					return rc; +				if (p->policyvers >= +					POLICYDB_VERSION_CONSTRAINT_NAMES) { +					rc = type_set_write(e->type_names, fp); +					if (rc) +						return rc; +				}  				break;  			default:  				break; @@ -2673,6 +2952,23 @@ static int class_write(void *vkey, void *datum, void *ptr)  	if (rc)  		return rc; +	if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { +		buf[0] = cpu_to_le32(cladatum->default_user); +		buf[1] = cpu_to_le32(cladatum->default_role); +		buf[2] = cpu_to_le32(cladatum->default_range); + +		rc = put_entry(buf, sizeof(uint32_t), 3, fp); +		if (rc) +			return rc; +	} + +	if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { +		buf[0] = cpu_to_le32(cladatum->default_type); +		rc = put_entry(buf, sizeof(uint32_t), 1, fp); +		if (rc) +			return rc; +	} +  	return 0;  } @@ -2959,7 +3255,7 @@ static int genfs_write(struct policydb *p, void *fp)  	return 0;  } -static int range_count(void *key, void *data, void *ptr) +static int hashtab_cnt(void *key, void *data, void *ptr)  {  	int *cnt = ptr;  	*cnt = *cnt + 1; @@ -2997,9 +3293,8 @@ static int range_write_helper(void *key, void *data, void *ptr)  static int range_write(struct policydb *p, void *fp)  { -	size_t nel;  	__le32 buf[1]; -	int rc; +	int rc, nel;  	struct policy_data pd;  	pd.p = p; @@ -3007,7 +3302,7 @@ static int range_write(struct policydb *p, void *fp)  	/* count the number of entries in the hashtab */  	nel = 0; -	rc = hashtab_map(p->range_tr, range_count, &nel); +	rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);  	if (rc)  		return rc; @@ -3024,6 +3319,63 @@ static int range_write(struct policydb *p, void *fp)  	return 0;  } +static int filename_write_helper(void *key, void *data, void *ptr) +{ +	__le32 buf[4]; +	struct filename_trans *ft = key; +	struct filename_trans_datum *otype = data; +	void *fp = ptr; +	int rc; +	u32 len; + +	len = strlen(ft->name); +	buf[0] = cpu_to_le32(len); +	rc = put_entry(buf, sizeof(u32), 1, fp); +	if (rc) +		return rc; + +	rc = put_entry(ft->name, sizeof(char), len, fp); +	if (rc) +		return rc; + +	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); + +	rc = put_entry(buf, sizeof(u32), 4, fp); +	if (rc) +		return rc; + +	return 0; +} + +static int filename_trans_write(struct policydb *p, void *fp) +{ +	u32 nel; +	__le32 buf[1]; +	int rc; + +	if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) +		return 0; + +	nel = 0; +	rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel); +	if (rc) +		return rc; + +	buf[0] = cpu_to_le32(nel); +	rc = put_entry(buf, sizeof(u32), 1, fp); +	if (rc) +		return rc; + +	rc = hashtab_map(p->filename_trans, filename_write_helper, fp); +	if (rc) +		return rc; + +	return 0; +} +  /*   * Write the configuration data in a policy database   * structure to a policy database binary representation @@ -3076,7 +3428,7 @@ int policydb_write(struct policydb *p, void *fp)  	if (!info) {  		printk(KERN_ERR "SELinux: compatibility lookup failed for policy "  		    "version %d", p->policyvers); -		return rc; +		return -EINVAL;  	}  	buf[0] = cpu_to_le32(p->policyvers); @@ -3126,7 +3478,7 @@ int policydb_write(struct policydb *p, void *fp)  	if (rc)  		return rc; -	rc = role_trans_write(p->role_tr, fp); +	rc = role_trans_write(p, fp);  	if (rc)  		return rc; @@ -3134,6 +3486,10 @@ int policydb_write(struct policydb *p, void *fp)  	if (rc)  		return rc; +	rc = filename_trans_write(p, fp); +	if (rc) +		return rc; +  	rc = ocontext_write(p, info, fp);  	if (rc)  		return rc;  | 
