diff options
Diffstat (limited to 'security/selinux/ss')
| -rw-r--r-- | security/selinux/ss/avtab.h | 23 | ||||
| -rw-r--r-- | security/selinux/ss/conditional.c | 12 | ||||
| -rw-r--r-- | security/selinux/ss/conditional.h | 1 | ||||
| -rw-r--r-- | security/selinux/ss/constraint.h | 1 | ||||
| -rw-r--r-- | security/selinux/ss/context.h | 20 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.c | 22 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.h | 11 | ||||
| -rw-r--r-- | security/selinux/ss/hashtab.c | 3 | ||||
| -rw-r--r-- | security/selinux/ss/mls.c | 80 | ||||
| -rw-r--r-- | security/selinux/ss/mls.h | 5 | ||||
| -rw-r--r-- | security/selinux/ss/mls_types.h | 2 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 1120 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 66 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 698 | ||||
| -rw-r--r-- | security/selinux/ss/sidtab.c | 39 | ||||
| -rw-r--r-- | security/selinux/ss/sidtab.h | 2 | 
16 files changed, 1341 insertions, 764 deletions
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index dff0c75345c..63ce2f9e441 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -14,7 +14,7 @@   *   * Copyright (C) 2003 Tresys Technology, LLC   *	This program is free software; you can redistribute it and/or modify - *  	it under the terms of the GNU General Public License as published by + *	it under the terms of the GNU General Public License as published by   *	the Free Software Foundation, version 2.   *   * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> @@ -27,16 +27,16 @@ struct avtab_key {  	u16 source_type;	/* source type */  	u16 target_type;	/* target type */  	u16 target_class;	/* target object class */ -#define AVTAB_ALLOWED     1 -#define AVTAB_AUDITALLOW  2 -#define AVTAB_AUDITDENY   4 -#define AVTAB_AV         (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) -#define AVTAB_TRANSITION 16 -#define AVTAB_MEMBER     32 -#define AVTAB_CHANGE     64 -#define AVTAB_TYPE       (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) -#define AVTAB_ENABLED_OLD    0x80000000 /* reserved for used in cond_avtab */ -#define AVTAB_ENABLED    0x8000 /* reserved for used in cond_avtab */ +#define AVTAB_ALLOWED		0x0001 +#define AVTAB_AUDITALLOW	0x0002 +#define AVTAB_AUDITDENY		0x0004 +#define AVTAB_AV		(AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) +#define AVTAB_TRANSITION	0x0010 +#define AVTAB_MEMBER		0x0020 +#define AVTAB_CHANGE		0x0040 +#define AVTAB_TYPE		(AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) +#define AVTAB_ENABLED_OLD   0x80000000 /* reserved for used in cond_avtab */ +#define AVTAB_ENABLED		0x8000 /* reserved for used in cond_avtab */  	u16 specified;	/* what field is specified */  }; @@ -86,7 +86,6 @@ void avtab_cache_destroy(void);  #define MAX_AVTAB_HASH_BITS 11  #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) -#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)  #endif	/* _SS_AVTAB_H_ */ diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 655fe1c6cc6..377d148e715 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -175,10 +175,10 @@ void cond_policydb_destroy(struct policydb *p)  int cond_init_bool_indexes(struct policydb *p)  {  	kfree(p->bool_val_to_struct); -	p->bool_val_to_struct = (struct cond_bool_datum **) +	p->bool_val_to_struct =  		kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);  	if (!p->bool_val_to_struct) -		return -1; +		return -ENOMEM;  	return 0;  } @@ -193,6 +193,7 @@ int cond_index_bool(void *key, void *datum, void *datap)  {  	struct policydb *p;  	struct cond_bool_datum *booldatum; +	struct flex_array *fa;  	booldatum = datum;  	p = datap; @@ -200,7 +201,10 @@ int cond_index_bool(void *key, void *datum, void *datap)  	if (!booldatum->value || booldatum->value > p->p_bools.nprim)  		return -EINVAL; -	p->p_bool_val_to_name[booldatum->value - 1] = key; +	fa = p->sym_val_to_name[SYM_BOOLS]; +	if (flex_array_put_ptr(fa, booldatum->value - 1, key, +			       GFP_KERNEL | __GFP_ZERO)) +		BUG();  	p->bool_val_to_struct[booldatum->value - 1] = booldatum;  	return 0; @@ -551,7 +555,7 @@ static int cond_write_av_list(struct policydb *p,  	return 0;  } -int cond_write_node(struct policydb *p, struct cond_node *node, +static int cond_write_node(struct policydb *p, struct cond_node *node,  		    struct policy_file *fp)  {  	struct cond_expr *cur_expr; diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 3f209c63529..4d1f8746650 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -13,6 +13,7 @@  #include "avtab.h"  #include "symtab.h"  #include "policydb.h" +#include "../include/conditional.h"  #define COND_EXPR_MAXDEPTH 10 diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h index 149dda731fd..96fd947c494 100644 --- a/security/selinux/ss/constraint.h +++ b/security/selinux/ss/constraint.h @@ -48,6 +48,7 @@ struct constraint_expr {  	u32 op;			/* operator */  	struct ebitmap names;	/* names */ +	struct type_set *type_names;  	struct constraint_expr *next;   /* next expression */  }; diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 45e8fb0515f..212e3479a0d 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -74,6 +74,26 @@ 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(struct context *dst, struct context *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(struct context *c1, struct context *c2)  {  	return ((c1->range.level[0].sens == c2->range.level[0].sens) && diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index d42951fcbe8..820313a04d4 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -4,7 +4,7 @@   * Author : Stephen Smalley, <sds@epoch.ncsc.mil>   */  /* - * Updated: Hewlett-Packard <paul.moore@hp.com> + * Updated: Hewlett-Packard <paul@paul-moore.com>   *   *      Added support to import/export the NetLabel category bitmap   * @@ -213,7 +213,12 @@ netlbl_import_failure:  }  #endif /* CONFIG_NETLABEL */ -int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) +/* + * Check to see if all the bits set in e2 are also set in e1. Optionally, + * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed + * last_e2bit. + */ +int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)  {  	struct ebitmap_node *n1, *n2;  	int i; @@ -223,14 +228,25 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)  	n1 = e1->node;  	n2 = e2->node; +  	while (n1 && n2 && (n1->startbit <= n2->startbit)) {  		if (n1->startbit < n2->startbit) {  			n1 = n1->next;  			continue;  		} -		for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { +		for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; ) +			i--;	/* Skip trailing NULL map entries */ +		if (last_e2bit && (i >= 0)) { +			u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE + +					 __fls(n2->maps[i]); +			if (lastsetbit > last_e2bit) +				return 0; +		} + +		while (i >= 0) {  			if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])  				return 0; +			i--;  		}  		n1 = n1->next; diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 1f4e93c2ae8..712c8a7b8e8 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -16,7 +16,13 @@  #include <net/netlabel.h> -#define EBITMAP_UNIT_NUMS	((32 - sizeof(void *) - sizeof(u32))	\ +#ifdef CONFIG_64BIT +#define	EBITMAP_NODE_SIZE	64 +#else +#define	EBITMAP_NODE_SIZE	32 +#endif + +#define EBITMAP_UNIT_NUMS	((EBITMAP_NODE_SIZE-sizeof(void *)-sizeof(u32))\  					/ sizeof(unsigned long))  #define EBITMAP_UNIT_SIZE	BITS_PER_LONG  #define EBITMAP_SIZE		(EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) @@ -36,7 +42,6 @@ struct ebitmap {  };  #define ebitmap_length(e) ((e)->highbit) -#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)  static inline unsigned int ebitmap_start_positive(struct ebitmap *e,  						  struct ebitmap_node **n) @@ -118,7 +123,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,  int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);  int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); -int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); +int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit);  int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);  int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);  void ebitmap_destroy(struct ebitmap *e); diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 933e735bb18..2cc49614984 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -6,6 +6,7 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/errno.h> +#include <linux/sched.h>  #include "hashtab.h"  struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), @@ -40,6 +41,8 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)  	u32 hvalue;  	struct hashtab_node *prev, *cur, *newnode; +	cond_resched(); +  	if (!h || h->nel == HASHTAB_MAX_NODES)  		return -EINVAL; diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index b4eff7a60c5..d307b37ddc2 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -11,7 +11,7 @@   * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.   */  /* - * Updated: Hewlett-Packard <paul.moore@hp.com> + * Updated: Hewlett-Packard <paul@paul-moore.com>   *   *      Added support to import/export the MLS label from NetLabel   * @@ -45,7 +45,7 @@ int mls_compute_context_len(struct context *context)  	len = 1; /* for the beginning ":" */  	for (l = 0; l < 2; l++) {  		int index_sens = context->range.level[l].sens; -		len += strlen(policydb.p_sens_val_to_name[index_sens - 1]); +		len += strlen(sym_name(&policydb, SYM_LEVELS, index_sens - 1));  		/* categories */  		head = -2; @@ -55,17 +55,17 @@ int mls_compute_context_len(struct context *context)  			if (i - prev > 1) {  				/* one or more negative bits are skipped */  				if (head != prev) { -					nm = policydb.p_cat_val_to_name[prev]; +					nm = sym_name(&policydb, SYM_CATS, prev);  					len += strlen(nm) + 1;  				} -				nm = policydb.p_cat_val_to_name[i]; +				nm = sym_name(&policydb, SYM_CATS, i);  				len += strlen(nm) + 1;  				head = i;  			}  			prev = i;  		}  		if (prev != head) { -			nm = policydb.p_cat_val_to_name[prev]; +			nm = sym_name(&policydb, SYM_CATS, prev);  			len += strlen(nm) + 1;  		}  		if (l == 0) { @@ -102,8 +102,8 @@ void mls_sid_to_context(struct context *context,  	scontextp++;  	for (l = 0; l < 2; l++) { -		strcpy(scontextp, -		       policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); +		strcpy(scontextp, sym_name(&policydb, SYM_LEVELS, +					   context->range.level[l].sens - 1));  		scontextp += strlen(scontextp);  		/* categories */ @@ -118,7 +118,7 @@ void mls_sid_to_context(struct context *context,  						*scontextp++ = '.';  					else  						*scontextp++ = ','; -					nm = policydb.p_cat_val_to_name[prev]; +					nm = sym_name(&policydb, SYM_CATS, prev);  					strcpy(scontextp, nm);  					scontextp += strlen(nm);  				} @@ -126,7 +126,7 @@ void mls_sid_to_context(struct context *context,  					*scontextp++ = ':';  				else  					*scontextp++ = ','; -				nm = policydb.p_cat_val_to_name[i]; +				nm = sym_name(&policydb, SYM_CATS, i);  				strcpy(scontextp, nm);  				scontextp += strlen(nm);  				head = i; @@ -139,7 +139,7 @@ void mls_sid_to_context(struct context *context,  				*scontextp++ = '.';  			else  				*scontextp++ = ','; -			nm = policydb.p_cat_val_to_name[prev]; +			nm = sym_name(&policydb, SYM_CATS, prev);  			strcpy(scontextp, nm);  			scontextp += strlen(nm);  		} @@ -160,29 +160,21 @@ void mls_sid_to_context(struct context *context,  int mls_level_isvalid(struct policydb *p, struct mls_level *l)  {  	struct level_datum *levdatum; -	struct ebitmap_node *node; -	int i;  	if (!l->sens || l->sens > p->p_levels.nprim)  		return 0;  	levdatum = hashtab_search(p->p_levels.table, -				  p->p_sens_val_to_name[l->sens - 1]); +				  sym_name(p, SYM_LEVELS, l->sens - 1));  	if (!levdatum)  		return 0; -	ebitmap_for_each_positive_bit(&l->cat, node, i) { -		if (i > p->p_cats.nprim) -			return 0; -		if (!ebitmap_get_bit(&levdatum->level->cat, i)) { -			/* -			 * Category may not be associated with -			 * sensitivity. -			 */ -			return 0; -		} -	} - -	return 1; +	/* +	 * Return 1 iff all the bits set in l->cat are also be set in +	 * levdatum->level->cat and no bit in l->cat is larger than +	 * p->p_cats.nprim. +	 */ +	return ebitmap_contains(&levdatum->level->cat, &l->cat, +				p->p_cats.nprim);  }  int mls_range_isvalid(struct policydb *p, struct mls_range *r) @@ -482,7 +474,8 @@ int mls_convert_context(struct policydb *oldp,  	for (l = 0; l < 2; l++) {  		levdatum = hashtab_search(newp->p_levels.table, -			oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); +					  sym_name(oldp, SYM_LEVELS, +						   c->range.level[l].sens - 1));  		if (!levdatum)  			return -EINVAL; @@ -493,12 +486,14 @@ int mls_convert_context(struct policydb *oldp,  			int rc;  			catdatum = hashtab_search(newp->p_cats.table, -						  oldp->p_cat_val_to_name[i]); +						  sym_name(oldp, SYM_CATS, i));  			if (!catdatum)  				return -EINVAL;  			rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);  			if (rc)  				return rc; + +			cond_resched();  		}  		ebitmap_destroy(&c->range.level[l].cat);  		c->range.level[l].cat = bitmap; @@ -511,10 +506,13 @@ int mls_compute_sid(struct context *scontext,  		    struct context *tcontext,  		    u16 tclass,  		    u32 specified, -		    struct context *newcontext) +		    struct context *newcontext, +		    bool sock)  {  	struct range_trans rtr;  	struct mls_range *r; +	struct class_datum *cladatum; +	int default_range = 0;  	if (!policydb.mls_enabled)  		return 0; @@ -528,9 +526,31 @@ int mls_compute_sid(struct context *scontext,  		r = hashtab_search(policydb.range_tr, &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 == policydb.process_class) +		if ((tclass == policydb.process_class) || (sock == true))  			/* Use the process MLS attributes. */  			return mls_context_cpy(newcontext, scontext);  		else diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index cd9152632e5..e4369e3e636 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -11,7 +11,7 @@   * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.   */  /* - * Updated: Hewlett-Packard <paul.moore@hp.com> + * Updated: Hewlett-Packard <paul@paul-moore.com>   *   *	Added support to import/export the MLS label from NetLabel   * @@ -49,7 +49,8 @@ int mls_compute_sid(struct context *scontext,  		    struct context *tcontext,  		    u16 tclass,  		    u32 specified, -		    struct context *newcontext); +		    struct context *newcontext, +		    bool sock);  int mls_setup_user_range(struct context *fromcon, struct user_datum *user,  			 struct context *usercon); diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index 03bed52a805..e9364877413 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -35,7 +35,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)  static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)  {  	return ((l1->sens >= l2->sens) && -		ebitmap_contains(&l1->cat, &l2->cat)); +		ebitmap_contains(&l1->cat, &l2->cat, 0));  }  #define mls_level_incomp(l1, l2) \ 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; diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 95d3d7de361..725d5945a97 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -60,6 +60,20 @@ struct class_datum {  	struct symtab permissions;	/* class-specific permission symbol table */  	struct constraint_node *constraints;	/* constraints on class permissions */  	struct constraint_node *validatetrans;	/* special transition rules */ +/* Options how a new object user, role, and type should be decided */ +#define DEFAULT_SOURCE         1 +#define DEFAULT_TARGET         2 +	char default_user; +	char default_role; +	char default_type; +/* Options how a new object range should be decided */ +#define DEFAULT_SOURCE_LOW     1 +#define DEFAULT_SOURCE_HIGH    2 +#define DEFAULT_SOURCE_LOW_HIGH        3 +#define DEFAULT_TARGET_LOW     4 +#define DEFAULT_TARGET_HIGH    5 +#define DEFAULT_TARGET_LOW_HIGH        6 +	char default_range;  };  /* Role attributes */ @@ -72,11 +86,23 @@ struct role_datum {  struct role_trans {  	u32 role;		/* current role */ -	u32 type;		/* program executable type */ +	u32 type;		/* program executable type, or new object type */ +	u32 tclass;		/* process class, or new object class */  	u32 new_role;		/* new role */  	struct role_trans *next;  }; +struct filename_trans { +	u32 stype;		/* current process */ +	u32 ttype;		/* parent dir context */ +	u16 tclass;		/* class of new object */ +	const char *name;	/* last path component */ +}; + +struct filename_trans_datum { +	u32 otype;		/* expected of new object */ +}; +  struct role_allow {  	u32 role;		/* current role */  	u32 new_role;		/* new role */ @@ -128,6 +154,17 @@ struct cond_bool_datum {  struct cond_node;  /* + * type set preserves data needed to determine constraint info from + * policy source. This is not used by the kernel policy but allows + * utilities such as audit2allow to determine constraint denials. + */ +struct type_set { +	struct ebitmap types; +	struct ebitmap negset; +	u32 flags; +}; + +/*   * The configuration data includes security contexts for   * initial SIDs, unlabeled file systems, TCP and UDP port numbers,   * network interfaces, and nodes.  This structure stores the @@ -203,21 +240,13 @@ struct policydb {  #define p_cats symtab[SYM_CATS]  	/* symbol names indexed by (value - 1) */ -	char **sym_val_to_name[SYM_NUM]; -#define p_common_val_to_name sym_val_to_name[SYM_COMMONS] -#define p_class_val_to_name sym_val_to_name[SYM_CLASSES] -#define p_role_val_to_name sym_val_to_name[SYM_ROLES] -#define p_type_val_to_name sym_val_to_name[SYM_TYPES] -#define p_user_val_to_name sym_val_to_name[SYM_USERS] -#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS] -#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS] -#define p_cat_val_to_name sym_val_to_name[SYM_CATS] +	struct flex_array *sym_val_to_name[SYM_NUM];  	/* class, role, and user attributes indexed by (value - 1) */  	struct class_datum **class_val_to_struct;  	struct role_datum **role_val_to_struct;  	struct user_datum **user_val_to_struct; -	struct type_datum **type_val_to_struct; +	struct flex_array *type_val_to_struct_array;  	/* type enforcement access vectors and transitions */  	struct avtab te_avtab; @@ -225,6 +254,12 @@ struct policydb {  	/* role transitions */  	struct role_trans *role_tr; +	/* file transitions with the last path component */ +	/* quickly exclude lookups when parent ttype has no rules */ +	struct ebitmap filename_trans_ttypes; +	/* actual set of filename_trans rules */ +	struct hashtab *filename_trans; +  	/* bools indexed by (value - 1) */  	struct cond_bool_datum **bool_val_to_struct;  	/* type enforcement conditional access vectors and transitions */ @@ -310,7 +345,7 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)  	return 0;  } -static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp) +static inline int put_entry(const void *buf, size_t bytes, int num, struct policy_file *fp)  {  	size_t len = bytes * num; @@ -321,6 +356,13 @@ static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file  	return 0;  } +static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned int element_nr) +{ +	struct flex_array *fa = p->sym_val_to_name[sym_num]; + +	return flex_array_get_ptr(fa, element_nr); +} +  extern u16 string_to_security_class(struct policydb *p, const char *name);  extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 223c1ff6ef2..4bca49414a4 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.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 NetLabel   *      Added support for the policy capability bitmap @@ -70,10 +70,9 @@  #include "ebitmap.h"  #include "audit.h" -extern void selnl_notify_policyload(u32 seqno); -  int selinux_policycap_netpeer;  int selinux_policycap_openperm; +int selinux_policycap_alwaysnetwork;  static DEFINE_RWLOCK(policy_rwlock); @@ -201,6 +200,21 @@ static u16 unmap_class(u16 tclass)  	return tclass;  } +/* + * Get kernel value for class from its policy value + */ +static u16 map_class(u16 pol_value) +{ +	u16 i; + +	for (i = 1; i < current_mapping_size; i++) { +		if (current_mapping[i].value == pol_value) +			return i; +	} + +	return SECCLASS_NULL; +} +  static void map_decision(u16 tclass, struct av_decision *avd,  			 int allow_unknown)  { @@ -464,7 +478,7 @@ static void security_dump_masked_av(struct context *scontext,  	if (!permissions)  		return; -	tclass_name = policydb.p_class_val_to_name[tclass - 1]; +	tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1);  	tclass_dat = policydb.class_val_to_struct[tclass - 1];  	common_dat = tclass_dat->comdatum; @@ -530,12 +544,18 @@ static void type_attribute_bounds_av(struct context *scontext,  	struct context lo_scontext;  	struct context lo_tcontext;  	struct av_decision lo_avd; -	struct type_datum *source -		= policydb.type_val_to_struct[scontext->type - 1]; -	struct type_datum *target -		= policydb.type_val_to_struct[tcontext->type - 1]; +	struct type_datum *source; +	struct type_datum *target;  	u32 masked = 0; +	source = flex_array_get_ptr(policydb.type_val_to_struct_array, +				    scontext->type - 1); +	BUG_ON(!source); + +	target = flex_array_get_ptr(policydb.type_val_to_struct_array, +				    tcontext->type - 1); +	BUG_ON(!target); +  	if (source->bounds) {  		memset(&lo_avd, 0, sizeof(lo_avd)); @@ -701,16 +721,16 @@ static int security_validtrans_handle_fail(struct context *ocontext,  	char *o = NULL, *n = NULL, *t = NULL;  	u32 olen, nlen, tlen; -	if (context_struct_to_string(ocontext, &o, &olen) < 0) +	if (context_struct_to_string(ocontext, &o, &olen))  		goto out; -	if (context_struct_to_string(ncontext, &n, &nlen) < 0) +	if (context_struct_to_string(ncontext, &n, &nlen))  		goto out; -	if (context_struct_to_string(tcontext, &t, &tlen) < 0) +	if (context_struct_to_string(tcontext, &t, &tlen))  		goto out;  	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,  		  "security_validate_transition:  denied for"  		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", -		  o, n, t, policydb.p_class_val_to_name[tclass-1]); +		  o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));  out:  	kfree(o);  	kfree(n); @@ -801,10 +821,11 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)  	struct context *old_context, *new_context;  	struct type_datum *type;  	int index; -	int rc = -EINVAL; +	int rc;  	read_lock(&policy_rwlock); +	rc = -EINVAL;  	old_context = sidtab_search(&sidtab, old_sid);  	if (!old_context) {  		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", @@ -812,6 +833,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)  		goto out;  	} +	rc = -EINVAL;  	new_context = sidtab_search(&sidtab, new_sid);  	if (!new_context) {  		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", @@ -819,28 +841,27 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)  		goto out;  	} +	rc = 0;  	/* type/domain unchanged */ -	if (old_context->type == new_context->type) { -		rc = 0; +	if (old_context->type == new_context->type)  		goto out; -	}  	index = new_context->type;  	while (true) { -		type = policydb.type_val_to_struct[index - 1]; +		type = flex_array_get_ptr(policydb.type_val_to_struct_array, +					  index - 1);  		BUG_ON(!type);  		/* not bounded anymore */ -		if (!type->bounds) { -			rc = -EPERM; +		rc = -EPERM; +		if (!type->bounds)  			break; -		}  		/* @newsid is bounded by @oldsid */ -		if (type->bounds == old_context->type) { -			rc = 0; +		rc = 0; +		if (type->bounds == old_context->type)  			break; -		} +  		index = type->bounds;  	} @@ -998,16 +1019,18 @@ static int context_struct_to_string(struct context *context, char **scontext, u3  	if (context->len) {  		*scontext_len = context->len; -		*scontext = kstrdup(context->str, GFP_ATOMIC); -		if (!(*scontext)) -			return -ENOMEM; +		if (scontext) { +			*scontext = kstrdup(context->str, GFP_ATOMIC); +			if (!(*scontext)) +				return -ENOMEM; +		}  		return 0;  	}  	/* Compute the size of the context. */ -	*scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; -	*scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; -	*scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; +	*scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1; +	*scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1; +	*scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1;  	*scontext_len += mls_compute_context_len(context);  	if (!scontext) @@ -1023,12 +1046,12 @@ static int context_struct_to_string(struct context *context, char **scontext, u3  	 * Copy the user name, role name and type name into the context.  	 */  	sprintf(scontextp, "%s:%s:%s", -		policydb.p_user_val_to_name[context->user - 1], -		policydb.p_role_val_to_name[context->role - 1], -		policydb.p_type_val_to_name[context->type - 1]); -	scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) + -		     1 + strlen(policydb.p_role_val_to_name[context->role - 1]) + -		     1 + strlen(policydb.p_type_val_to_name[context->type - 1]); +		sym_name(&policydb, SYM_USERS, context->user - 1), +		sym_name(&policydb, SYM_ROLES, context->role - 1), +		sym_name(&policydb, SYM_TYPES, context->type - 1)); +	scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + +		     1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + +		     1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));  	mls_sid_to_context(context, &scontextp); @@ -1187,16 +1210,13 @@ static int string_to_context_struct(struct policydb *pol,  	if (rc)  		goto out; -	if ((p - scontext) < scontext_len) { -		rc = -EINVAL; +	rc = -EINVAL; +	if ((p - scontext) < scontext_len)  		goto out; -	}  	/* Check the validity of the new context. */ -	if (!policydb_context_isvalid(pol, ctx)) { -		rc = -EINVAL; +	if (!policydb_context_isvalid(pol, ctx))  		goto out; -	}  	rc = 0;  out:  	if (rc) @@ -1212,6 +1232,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,  	struct context context;  	int rc = 0; +	/* An empty security context is never valid. */ +	if (!scontext_len) +		return -EINVAL; +  	if (!ss_initialized) {  		int i; @@ -1235,27 +1259,26 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,  	if (force) {  		/* Save another copy for storing in uninterpreted form */ +		rc = -ENOMEM;  		str = kstrdup(scontext2, gfp_flags); -		if (!str) { -			kfree(scontext2); -			return -ENOMEM; -		} +		if (!str) +			goto out;  	}  	read_lock(&policy_rwlock); -	rc = string_to_context_struct(&policydb, &sidtab, -				      scontext2, scontext_len, -				      &context, def_sid); +	rc = string_to_context_struct(&policydb, &sidtab, scontext2, +				      scontext_len, &context, def_sid);  	if (rc == -EINVAL && force) {  		context.str = str;  		context.len = scontext_len;  		str = NULL;  	} else if (rc) -		goto out; +		goto out_unlock;  	rc = sidtab_context_to_sid(&sidtab, &context, sid);  	context_destroy(&context); -out: +out_unlock:  	read_unlock(&policy_rwlock); +out:  	kfree(scontext2);  	kfree(str);  	return rc; @@ -1266,16 +1289,18 @@ out:   * @scontext: security context   * @scontext_len: length in bytes   * @sid: security identifier, SID + * @gfp: context for the allocation   *   * Obtains a SID associated with the security context that   * has the string representation specified by @scontext.   * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient   * memory is available, or 0 on success.   */ -int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) +int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, +			    gfp_t gfp)  {  	return security_context_to_sid_core(scontext, scontext_len, -					    sid, SECSID_NULL, GFP_KERNEL, 0); +					    sid, SECSID_NULL, gfp, 0);  }  /** @@ -1319,18 +1344,18 @@ static int compute_sid_handle_invalid_context(  	char *s = NULL, *t = NULL, *n = NULL;  	u32 slen, tlen, nlen; -	if (context_struct_to_string(scontext, &s, &slen) < 0) +	if (context_struct_to_string(scontext, &s, &slen))  		goto out; -	if (context_struct_to_string(tcontext, &t, &tlen) < 0) +	if (context_struct_to_string(tcontext, &t, &tlen))  		goto out; -	if (context_struct_to_string(newcontext, &n, &nlen) < 0) +	if (context_struct_to_string(newcontext, &n, &nlen))  		goto out;  	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,  		  "security_compute_sid:  invalid context %s"  		  " for scontext=%s"  		  " tcontext=%s"  		  " tclass=%s", -		  n, s, t, policydb.p_class_val_to_name[tclass-1]); +		  n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));  out:  	kfree(s);  	kfree(t); @@ -1340,13 +1365,40 @@ out:  	return -EACCES;  } +static void filename_compute_type(struct policydb *p, struct context *newcontext, +				  u32 stype, u32 ttype, u16 tclass, +				  const char *objname) +{ +	struct filename_trans ft; +	struct filename_trans_datum *otype; + +	/* +	 * Most filename trans rules are going to live in specific directories +	 * like /dev or /var/run.  This bitmap will quickly skip rule searches +	 * if the ttype does not contain any rules. +	 */ +	if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) +		return; + +	ft.stype = stype; +	ft.ttype = ttype; +	ft.tclass = tclass; +	ft.name = objname; + +	otype = hashtab_search(p->filename_trans, &ft); +	if (otype) +		newcontext->type = otype->otype; +} +  static int security_compute_sid(u32 ssid,  				u32 tsid,  				u16 orig_tclass,  				u32 specified, +				const char *objname,  				u32 *out_sid,  				bool kern)  { +	struct class_datum *cladatum = NULL;  	struct context *scontext = NULL, *tcontext = NULL, newcontext;  	struct role_trans *roletr = NULL;  	struct avtab_key avkey; @@ -1354,6 +1406,7 @@ static int security_compute_sid(u32 ssid,  	struct avtab_node *node;  	u16 tclass;  	int rc = 0; +	bool sock;  	if (!ss_initialized) {  		switch (orig_tclass) { @@ -1371,10 +1424,13 @@ static int security_compute_sid(u32 ssid,  	read_lock(&policy_rwlock); -	if (kern) +	if (kern) {  		tclass = unmap_class(orig_tclass); -	else +		sock = security_is_socket_class(orig_tclass); +	} else {  		tclass = orig_tclass; +		sock = security_is_socket_class(map_class(tclass)); +	}  	scontext = sidtab_search(&sidtab, ssid);  	if (!scontext) { @@ -1391,12 +1447,20 @@ static int security_compute_sid(u32 ssid,  		goto out_unlock;  	} +	if (tclass && tclass <= policydb.p_classes.nprim) +		cladatum = policydb.class_val_to_struct[tclass - 1]; +  	/* Set the user identity. */  	switch (specified) {  	case AVTAB_TRANSITION:  	case AVTAB_CHANGE: -		/* Use the process user identity. */ -		newcontext.user = scontext->user; +		if (cladatum && cladatum->default_user == DEFAULT_TARGET) { +			newcontext.user = tcontext->user; +		} else { +			/* notice this gets both DEFAULT_SOURCE and unset */ +			/* Use the process user identity. */ +			newcontext.user = scontext->user; +		}  		break;  	case AVTAB_MEMBER:  		/* Use the related object owner. */ @@ -1404,16 +1468,31 @@ static int security_compute_sid(u32 ssid,  		break;  	} -	/* Set the role and type to default values. */ -	if (tclass == policydb.process_class) { -		/* Use the current role and type of process. */ +	/* Set the role to default values. */ +	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {  		newcontext.role = scontext->role; -		newcontext.type = scontext->type; +	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { +		newcontext.role = tcontext->role;  	} else { -		/* Use the well-defined object role. */ -		newcontext.role = OBJECT_R_VAL; -		/* Use the type of the related object. */ +		if ((tclass == policydb.process_class) || (sock == true)) +			newcontext.role = scontext->role; +		else +			newcontext.role = OBJECT_R_VAL; +	} + +	/* Set the type to default values. */ +	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { +		newcontext.type = scontext->type; +	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {  		newcontext.type = tcontext->type; +	} else { +		if ((tclass == policydb.process_class) || (sock == true)) { +			/* Use the type of process. */ +			newcontext.type = scontext->type; +		} else { +			/* Use the type of the related object. */ +			newcontext.type = tcontext->type; +		}  	}  	/* Look for a type transition/member/change rule. */ @@ -1439,25 +1518,29 @@ static int security_compute_sid(u32 ssid,  		newcontext.type = avdatum->data;  	} +	/* if we have a objname this is a file trans check so check those rules */ +	if (objname) +		filename_compute_type(&policydb, &newcontext, scontext->type, +				      tcontext->type, tclass, objname); +  	/* Check for class-specific changes. */ -	if  (tclass == policydb.process_class) { -		if (specified & AVTAB_TRANSITION) { -			/* Look for a role transition rule. */ -			for (roletr = policydb.role_tr; roletr; -			     roletr = roletr->next) { -				if (roletr->role == scontext->role && -				    roletr->type == tcontext->type) { -					/* Use the role transition rule. */ -					newcontext.role = roletr->new_role; -					break; -				} +	if (specified & AVTAB_TRANSITION) { +		/* Look for a role transition rule. */ +		for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { +			if ((roletr->role == scontext->role) && +			    (roletr->type == tcontext->type) && +			    (roletr->tclass == tclass)) { +				/* Use the role transition rule. */ +				newcontext.role = roletr->new_role; +				break;  			}  		}  	}  	/* Set the MLS attributes.  	   This is done last because it may allocate memory. */ -	rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext); +	rc = mls_compute_sid(scontext, tcontext, tclass, specified, +			     &newcontext, sock);  	if (rc)  		goto out_unlock; @@ -1492,22 +1575,18 @@ out:   * if insufficient memory is available, or %0 if the new SID was   * computed successfully.   */ -int security_transition_sid(u32 ssid, -			    u32 tsid, -			    u16 tclass, -			    u32 *out_sid) +int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, +			    const struct qstr *qstr, u32 *out_sid)  {  	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, -				    out_sid, true); +				    qstr ? qstr->name : NULL, out_sid, true);  } -int security_transition_sid_user(u32 ssid, -				 u32 tsid, -				 u16 tclass, -				 u32 *out_sid) +int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, +				 const char *objname, u32 *out_sid)  {  	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, -				    out_sid, false); +				    objname, out_sid, false);  }  /** @@ -1528,8 +1607,8 @@ int security_member_sid(u32 ssid,  			u16 tclass,  			u32 *out_sid)  { -	return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid, -				    false); +	return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL, +				    out_sid, false);  }  /** @@ -1550,8 +1629,8 @@ int security_change_sid(u32 ssid,  			u16 tclass,  			u32 *out_sid)  { -	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid, -				    false); +	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, +				    out_sid, false);  }  /* Clone the SID into the new SID table. */ @@ -1569,22 +1648,17 @@ static int clone_sid(u32 sid,  static inline int convert_context_handle_invalid_context(struct context *context)  { -	int rc = 0; +	char *s; +	u32 len; -	if (selinux_enforcing) { -		rc = -EINVAL; -	} else { -		char *s; -		u32 len; - -		if (!context_struct_to_string(context, &s, &len)) { -			printk(KERN_WARNING -		       "SELinux:  Context %s would be invalid if enforcing\n", -			       s); -			kfree(s); -		} +	if (selinux_enforcing) +		return -EINVAL; + +	if (!context_struct_to_string(context, &s, &len)) { +		printk(KERN_WARNING "SELinux:  Context %s would be invalid if enforcing\n", s); +		kfree(s);  	} -	return rc; +	return 0;  }  struct convert_context_args { @@ -1621,17 +1695,17 @@ static int convert_context(u32 key,  	if (c->str) {  		struct context ctx; + +		rc = -ENOMEM;  		s = kstrdup(c->str, GFP_KERNEL); -		if (!s) { -			rc = -ENOMEM; +		if (!s)  			goto out; -		} +  		rc = string_to_context_struct(args->newp, NULL, s,  					      c->len, &ctx, SECSID_NULL);  		kfree(s);  		if (!rc) { -			printk(KERN_INFO -		       "SELinux:  Context %s became valid (mapped).\n", +			printk(KERN_INFO "SELinux:  Context %s became valid (mapped).\n",  			       c->str);  			/* Replace string with mapped representation. */  			kfree(c->str); @@ -1643,8 +1717,7 @@ static int convert_context(u32 key,  			goto out;  		} else {  			/* Other error condition, e.g. ENOMEM. */ -			printk(KERN_ERR -		       "SELinux:   Unable to map context %s, rc = %d.\n", +			printk(KERN_ERR "SELinux:   Unable to map context %s, rc = %d.\n",  			       c->str, -rc);  			goto out;  		} @@ -1654,25 +1727,26 @@ static int convert_context(u32 key,  	if (rc)  		goto out; -	rc = -EINVAL; -  	/* Convert the user. */ +	rc = -EINVAL;  	usrdatum = hashtab_search(args->newp->p_users.table, -				  args->oldp->p_user_val_to_name[c->user - 1]); +				  sym_name(args->oldp, SYM_USERS, c->user - 1));  	if (!usrdatum)  		goto bad;  	c->user = usrdatum->value;  	/* Convert the role. */ +	rc = -EINVAL;  	role = hashtab_search(args->newp->p_roles.table, -			      args->oldp->p_role_val_to_name[c->role - 1]); +			      sym_name(args->oldp, SYM_ROLES, c->role - 1));  	if (!role)  		goto bad;  	c->role = role->value;  	/* Convert the type. */ +	rc = -EINVAL;  	typdatum = hashtab_search(args->newp->p_types.table, -				  args->oldp->p_type_val_to_name[c->type - 1]); +				  sym_name(args->oldp, SYM_TYPES, c->type - 1));  	if (!typdatum)  		goto bad;  	c->type = typdatum->value; @@ -1700,6 +1774,7 @@ static int convert_context(u32 key,  		oc = args->newp->ocontexts[OCON_ISID];  		while (oc && oc->sid[0] != SECINITSID_UNLABELED)  			oc = oc->next; +		rc = -EINVAL;  		if (!oc) {  			printk(KERN_ERR "SELinux:  unable to look up"  				" the initial SIDs list\n"); @@ -1719,19 +1794,20 @@ static int convert_context(u32 key,  	}  	context_destroy(&oldc); +  	rc = 0;  out:  	return rc;  bad:  	/* Map old representation to string and save it. */ -	if (context_struct_to_string(&oldc, &s, &len)) -		return -ENOMEM; +	rc = context_struct_to_string(&oldc, &s, &len); +	if (rc) +		return rc;  	context_destroy(&oldc);  	context_destroy(c);  	c->str = s;  	c->len = len; -	printk(KERN_INFO -	       "SELinux:  Context %s became invalid (unmapped).\n", +	printk(KERN_INFO "SELinux:  Context %s became invalid (unmapped).\n",  	       c->str);  	rc = 0;  	goto out; @@ -1743,9 +1819,10 @@ static void security_load_policycaps(void)  						  POLICYDB_CAPABILITY_NETPEER);  	selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,  						  POLICYDB_CAPABILITY_OPENPERM); +	selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, +						  POLICYDB_CAPABILITY_ALWAYSNETWORK);  } -extern void selinux_complete_init(void);  static int security_preserve_bools(struct policydb *p);  /** @@ -1760,7 +1837,7 @@ static int security_preserve_bools(struct policydb *p);   */  int security_load_policy(void *data, size_t len)  { -	struct policydb oldpolicydb, newpolicydb; +	struct policydb *oldpolicydb, *newpolicydb;  	struct sidtab oldsidtab, newsidtab;  	struct selinux_mapping *oldmap, *map = NULL;  	struct convert_context_args args; @@ -1769,12 +1846,19 @@ int security_load_policy(void *data, size_t len)  	int rc = 0;  	struct policy_file file = { data, len }, *fp = &file; +	oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); +	if (!oldpolicydb) { +		rc = -ENOMEM; +		goto out; +	} +	newpolicydb = oldpolicydb + 1; +  	if (!ss_initialized) {  		avtab_cache_init();  		rc = policydb_read(&policydb, fp);  		if (rc) {  			avtab_cache_destroy(); -			return rc; +			goto out;  		}  		policydb.len = len; @@ -1784,14 +1868,14 @@ int security_load_policy(void *data, size_t len)  		if (rc) {  			policydb_destroy(&policydb);  			avtab_cache_destroy(); -			return rc; +			goto out;  		}  		rc = policydb_load_isids(&policydb, &sidtab);  		if (rc) {  			policydb_destroy(&policydb);  			avtab_cache_destroy(); -			return rc; +			goto out;  		}  		security_load_policycaps(); @@ -1803,36 +1887,36 @@ int security_load_policy(void *data, size_t len)  		selinux_status_update_policyload(seqno);  		selinux_netlbl_cache_invalidate();  		selinux_xfrm_notify_policyload(); -		return 0; +		goto out;  	}  #if 0  	sidtab_hash_eval(&sidtab, "sids");  #endif -	rc = policydb_read(&newpolicydb, fp); +	rc = policydb_read(newpolicydb, fp);  	if (rc) -		return rc; +		goto out; -	newpolicydb.len = len; +	newpolicydb->len = len;  	/* If switching between different policy types, log MLS status */ -	if (policydb.mls_enabled && !newpolicydb.mls_enabled) +	if (policydb.mls_enabled && !newpolicydb->mls_enabled)  		printk(KERN_INFO "SELinux: Disabling MLS support...\n"); -	else if (!policydb.mls_enabled && newpolicydb.mls_enabled) +	else if (!policydb.mls_enabled && newpolicydb->mls_enabled)  		printk(KERN_INFO "SELinux: Enabling MLS support...\n"); -	rc = policydb_load_isids(&newpolicydb, &newsidtab); +	rc = policydb_load_isids(newpolicydb, &newsidtab);  	if (rc) {  		printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n"); -		policydb_destroy(&newpolicydb); -		return rc; +		policydb_destroy(newpolicydb); +		goto out;  	} -	rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); +	rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);  	if (rc)  		goto err; -	rc = security_preserve_bools(&newpolicydb); +	rc = security_preserve_bools(newpolicydb);  	if (rc) {  		printk(KERN_ERR "SELinux:  unable to preserve booleans\n");  		goto err; @@ -1850,7 +1934,7 @@ int security_load_policy(void *data, size_t len)  	 * in the new SID table.  	 */  	args.oldp = &policydb; -	args.newp = &newpolicydb; +	args.newp = newpolicydb;  	rc = sidtab_map(&newsidtab, convert_context, &args);  	if (rc) {  		printk(KERN_ERR "SELinux:  unable to convert the internal" @@ -1860,12 +1944,12 @@ int security_load_policy(void *data, size_t len)  	}  	/* Save the old policydb and SID table to free later. */ -	memcpy(&oldpolicydb, &policydb, sizeof policydb); +	memcpy(oldpolicydb, &policydb, sizeof(policydb));  	sidtab_set(&oldsidtab, &sidtab);  	/* Install the new policydb and SID table. */  	write_lock_irq(&policy_rwlock); -	memcpy(&policydb, &newpolicydb, sizeof policydb); +	memcpy(&policydb, newpolicydb, sizeof(policydb));  	sidtab_set(&sidtab, &newsidtab);  	security_load_policycaps();  	oldmap = current_mapping; @@ -1875,7 +1959,7 @@ int security_load_policy(void *data, size_t len)  	write_unlock_irq(&policy_rwlock);  	/* Free the old policydb and SID table. */ -	policydb_destroy(&oldpolicydb); +	policydb_destroy(oldpolicydb);  	sidtab_destroy(&oldsidtab);  	kfree(oldmap); @@ -1885,14 +1969,17 @@ int security_load_policy(void *data, size_t len)  	selinux_netlbl_cache_invalidate();  	selinux_xfrm_notify_policyload(); -	return 0; +	rc = 0; +	goto out;  err:  	kfree(map);  	sidtab_destroy(&newsidtab); -	policydb_destroy(&newpolicydb); -	return rc; +	policydb_destroy(newpolicydb); +out: +	kfree(oldpolicydb); +	return rc;  }  size_t security_policydb_len(void) @@ -2012,7 +2099,7 @@ int security_node_sid(u16 domain,  		      u32 addrlen,  		      u32 *out_sid)  { -	int rc = 0; +	int rc;  	struct ocontext *c;  	read_lock(&policy_rwlock); @@ -2021,10 +2108,9 @@ int security_node_sid(u16 domain,  	case AF_INET: {  		u32 addr; -		if (addrlen != sizeof(u32)) { -			rc = -EINVAL; +		rc = -EINVAL; +		if (addrlen != sizeof(u32))  			goto out; -		}  		addr = *((u32 *)addrp); @@ -2038,10 +2124,9 @@ int security_node_sid(u16 domain,  	}  	case AF_INET6: -		if (addrlen != sizeof(u64) * 2) { -			rc = -EINVAL; +		rc = -EINVAL; +		if (addrlen != sizeof(u64) * 2)  			goto out; -		}  		c = policydb.ocontexts[OCON_NODE6];  		while (c) {  			if (match_ipv6_addrmask(addrp, c->u.node6.addr, @@ -2052,6 +2137,7 @@ int security_node_sid(u16 domain,  		break;  	default: +		rc = 0;  		*out_sid = SECINITSID_NODE;  		goto out;  	} @@ -2069,6 +2155,7 @@ int security_node_sid(u16 domain,  		*out_sid = SECINITSID_NODE;  	} +	rc = 0;  out:  	read_unlock(&policy_rwlock);  	return rc; @@ -2113,24 +2200,22 @@ int security_get_user_sids(u32 fromsid,  	context_init(&usercon); +	rc = -EINVAL;  	fromcon = sidtab_search(&sidtab, fromsid); -	if (!fromcon) { -		rc = -EINVAL; +	if (!fromcon)  		goto out_unlock; -	} +	rc = -EINVAL;  	user = hashtab_search(policydb.p_users.table, username); -	if (!user) { -		rc = -EINVAL; +	if (!user)  		goto out_unlock; -	} +  	usercon.user = user->value; +	rc = -ENOMEM;  	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); -	if (!mysids) { -		rc = -ENOMEM; +	if (!mysids)  		goto out_unlock; -	}  	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {  		role = policydb.role_val_to_struct[i]; @@ -2147,12 +2232,11 @@ int security_get_user_sids(u32 fromsid,  			if (mynel < maxnel) {  				mysids[mynel++] = sid;  			} else { +				rc = -ENOMEM;  				maxnel += SIDS_NEL;  				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); -				if (!mysids2) { -					rc = -ENOMEM; +				if (!mysids2)  					goto out_unlock; -				}  				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));  				kfree(mysids);  				mysids = mysids2; @@ -2160,7 +2244,7 @@ int security_get_user_sids(u32 fromsid,  			}  		}  	} - +	rc = 0;  out_unlock:  	read_unlock(&policy_rwlock);  	if (rc || !mynel) { @@ -2168,17 +2252,18 @@ out_unlock:  		goto out;  	} +	rc = -ENOMEM;  	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);  	if (!mysids2) { -		rc = -ENOMEM;  		kfree(mysids);  		goto out;  	}  	for (i = 0, j = 0; i < mynel; i++) { +		struct av_decision dummy_avd;  		rc = avc_has_perm_noaudit(fromsid, mysids[i],  					  SECCLASS_PROCESS, /* kernel value */  					  PROCESS__TRANSITION, AVC_STRICT, -					  NULL); +					  &dummy_avd);  		if (!rc)  			mysids2[j++] = mysids[i];  		cond_resched(); @@ -2211,7 +2296,7 @@ int security_genfs_sid(const char *fstype,  	u16 sclass;  	struct genfs *genfs;  	struct ocontext *c; -	int rc = 0, cmp = 0; +	int rc, cmp = 0;  	while (path[0] == '/' && path[1] == '/')  		path++; @@ -2219,6 +2304,7 @@ int security_genfs_sid(const char *fstype,  	read_lock(&policy_rwlock);  	sclass = unmap_class(orig_sclass); +	*sid = SECINITSID_UNLABELED;  	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {  		cmp = strcmp(fstype, genfs->fstype); @@ -2226,11 +2312,9 @@ int security_genfs_sid(const char *fstype,  			break;  	} -	if (!genfs || cmp) { -		*sid = SECINITSID_UNLABELED; -		rc = -ENOENT; +	rc = -ENOENT; +	if (!genfs || cmp)  		goto out; -	}  	for (c = genfs->head; c; c = c->next) {  		len = strlen(c->u.name); @@ -2239,21 +2323,18 @@ int security_genfs_sid(const char *fstype,  			break;  	} -	if (!c) { -		*sid = SECINITSID_UNLABELED; -		rc = -ENOENT; +	rc = -ENOENT; +	if (!c)  		goto out; -	}  	if (!c->sid[0]) { -		rc = sidtab_context_to_sid(&sidtab, -					   &c->context[0], -					   &c->sid[0]); +		rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);  		if (rc)  			goto out;  	}  	*sid = c->sid[0]; +	rc = 0;  out:  	read_unlock(&policy_rwlock);  	return rc; @@ -2261,17 +2342,14 @@ out:  /**   * security_fs_use - Determine how to handle labeling for a filesystem. - * @fstype: filesystem type - * @behavior: labeling behavior - * @sid: SID for filesystem (superblock) + * @sb: superblock in question   */ -int security_fs_use( -	const char *fstype, -	unsigned int *behavior, -	u32 *sid) +int security_fs_use(struct super_block *sb)  {  	int rc = 0;  	struct ocontext *c; +	struct superblock_security_struct *sbsec = sb->s_security; +	const char *fstype = sb->s_type->name;  	read_lock(&policy_rwlock); @@ -2283,22 +2361,21 @@ int security_fs_use(  	}  	if (c) { -		*behavior = c->v.behavior; +		sbsec->behavior = c->v.behavior;  		if (!c->sid[0]) { -			rc = sidtab_context_to_sid(&sidtab, -						   &c->context[0], +			rc = sidtab_context_to_sid(&sidtab, &c->context[0],  						   &c->sid[0]);  			if (rc)  				goto out;  		} -		*sid = c->sid[0]; +		sbsec->sid = c->sid[0];  	} else { -		rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); +		rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid);  		if (rc) { -			*behavior = SECURITY_FS_USE_NONE; +			sbsec->behavior = SECURITY_FS_USE_NONE;  			rc = 0;  		} else { -			*behavior = SECURITY_FS_USE_GENFS; +			sbsec->behavior = SECURITY_FS_USE_GENFS;  		}  	} @@ -2309,34 +2386,39 @@ out:  int security_get_bools(int *len, char ***names, int **values)  { -	int i, rc = -ENOMEM; +	int i, rc;  	read_lock(&policy_rwlock);  	*names = NULL;  	*values = NULL; +	rc = 0;  	*len = policydb.p_bools.nprim; -	if (!*len) { -		rc = 0; +	if (!*len)  		goto out; -	} -       *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); +	rc = -ENOMEM; +	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);  	if (!*names)  		goto err; -       *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); +	rc = -ENOMEM; +	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);  	if (!*values)  		goto err;  	for (i = 0; i < *len; i++) {  		size_t name_len; +  		(*values)[i] = policydb.bool_val_to_struct[i]->state; -		name_len = strlen(policydb.p_bool_val_to_name[i]) + 1; -	       (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); +		name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1; + +		rc = -ENOMEM; +		(*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);  		if (!(*names)[i])  			goto err; -		strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len); + +		strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);  		(*names)[i][name_len - 1] = 0;  	}  	rc = 0; @@ -2355,27 +2437,26 @@ err:  int security_set_bools(int len, int *values)  { -	int i, rc = 0; +	int i, rc;  	int lenp, seqno = 0;  	struct cond_node *cur;  	write_lock_irq(&policy_rwlock); +	rc = -EFAULT;  	lenp = policydb.p_bools.nprim; -	if (len != lenp) { -		rc = -EFAULT; +	if (len != lenp)  		goto out; -	}  	for (i = 0; i < len; i++) {  		if (!!values[i] != policydb.bool_val_to_struct[i]->state) {  			audit_log(current->audit_context, GFP_ATOMIC,  				AUDIT_MAC_CONFIG_CHANGE,  				"bool=%s val=%d old_val=%d auid=%u ses=%u", -				policydb.p_bool_val_to_name[i], +				sym_name(&policydb, SYM_BOOLS, i),  				!!values[i],  				policydb.bool_val_to_struct[i]->state, -				audit_get_loginuid(current), +				from_kuid(&init_user_ns, audit_get_loginuid(current)),  				audit_get_sessionid(current));  		}  		if (values[i]) @@ -2391,7 +2472,7 @@ int security_set_bools(int len, int *values)  	}  	seqno = ++latest_granting; - +	rc = 0;  out:  	write_unlock_irq(&policy_rwlock);  	if (!rc) { @@ -2405,16 +2486,15 @@ out:  int security_get_bool_value(int bool)  { -	int rc = 0; +	int rc;  	int len;  	read_lock(&policy_rwlock); +	rc = -EFAULT;  	len = policydb.p_bools.nprim; -	if (bool >= len) { -		rc = -EFAULT; +	if (bool >= len)  		goto out; -	}  	rc = policydb.bool_val_to_struct[bool]->state;  out: @@ -2464,8 +2544,9 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)  	struct context newcon;  	char *s;  	u32 len; -	int rc = 0; +	int rc; +	rc = 0;  	if (!ss_initialized || !policydb.mls_enabled) {  		*new_sid = sid;  		goto out; @@ -2474,19 +2555,20 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)  	context_init(&newcon);  	read_lock(&policy_rwlock); + +	rc = -EINVAL;  	context1 = sidtab_search(&sidtab, sid);  	if (!context1) {  		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  			__func__, sid); -		rc = -EINVAL;  		goto out_unlock;  	} +	rc = -EINVAL;  	context2 = sidtab_search(&sidtab, mls_sid);  	if (!context2) {  		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  			__func__, mls_sid); -		rc = -EINVAL;  		goto out_unlock;  	} @@ -2500,20 +2582,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)  	/* Check the validity of the new context. */  	if (!policydb_context_isvalid(&policydb, &newcon)) {  		rc = convert_context_handle_invalid_context(&newcon); -		if (rc) -			goto bad; +		if (rc) { +			if (!context_struct_to_string(&newcon, &s, &len)) { +				audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, +					  "security_sid_mls_copy: invalid context %s", s); +				kfree(s); +			} +			goto out_unlock; +		}  	}  	rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); -	goto out_unlock; - -bad: -	if (!context_struct_to_string(&newcon, &s, &len)) { -		audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, -			  "security_sid_mls_copy: invalid context %s", s); -		kfree(s); -	} -  out_unlock:  	read_unlock(&policy_rwlock);  	context_destroy(&newcon); @@ -2549,6 +2628,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,  	struct context *nlbl_ctx;  	struct context *xfrm_ctx; +	*peer_sid = SECSID_NULL; +  	/* handle the common (which also happens to be the set of easy) cases  	 * right away, these two if statements catch everything involving a  	 * single or absent peer SID/label */ @@ -2567,40 +2648,37 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,  	/* we don't need to check ss_initialized here since the only way both  	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the  	 * security server was initialized and ss_initialized was true */ -	if (!policydb.mls_enabled) { -		*peer_sid = SECSID_NULL; +	if (!policydb.mls_enabled)  		return 0; -	}  	read_lock(&policy_rwlock); +	rc = -EINVAL;  	nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);  	if (!nlbl_ctx) {  		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  		       __func__, nlbl_sid); -		rc = -EINVAL; -		goto out_slowpath; +		goto out;  	} +	rc = -EINVAL;  	xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);  	if (!xfrm_ctx) {  		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  		       __func__, xfrm_sid); -		rc = -EINVAL; -		goto out_slowpath; +		goto out;  	}  	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); +	if (rc) +		goto out; -out_slowpath: +	/* at present NetLabel SIDs/labels really only carry MLS +	 * information so if the MLS portion of the NetLabel SID +	 * matches the MLS portion of the labeled XFRM SID/label +	 * then pass along the XFRM SID as it is the most +	 * expressive */ +	*peer_sid = xfrm_sid; +out:  	read_unlock(&policy_rwlock); -	if (rc == 0) -		/* at present NetLabel SIDs/labels really only carry MLS -		 * information so if the MLS portion of the NetLabel SID -		 * matches the MLS portion of the labeled XFRM SID/label -		 * then pass along the XFRM SID as it is the most -		 * expressive */ -		*peer_sid = xfrm_sid; -	else -		*peer_sid = SECSID_NULL;  	return rc;  } @@ -2619,10 +2697,11 @@ static int get_classes_callback(void *k, void *d, void *args)  int security_get_classes(char ***classes, int *nclasses)  { -	int rc = -ENOMEM; +	int rc;  	read_lock(&policy_rwlock); +	rc = -ENOMEM;  	*nclasses = policydb.p_classes.nprim;  	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);  	if (!*classes) @@ -2630,7 +2709,7 @@ int security_get_classes(char ***classes, int *nclasses)  	rc = hashtab_map(policydb.p_classes.table, get_classes_callback,  			*classes); -	if (rc < 0) { +	if (rc) {  		int i;  		for (i = 0; i < *nclasses; i++)  			kfree((*classes)[i]); @@ -2657,19 +2736,20 @@ static int get_permissions_callback(void *k, void *d, void *args)  int security_get_permissions(char *class, char ***perms, int *nperms)  { -	int rc = -ENOMEM, i; +	int rc, i;  	struct class_datum *match;  	read_lock(&policy_rwlock); +	rc = -EINVAL;  	match = hashtab_search(policydb.p_classes.table, class);  	if (!match) {  		printk(KERN_ERR "SELinux: %s:  unrecognized class %s\n",  			__func__, class); -		rc = -EINVAL;  		goto out;  	} +	rc = -ENOMEM;  	*nperms = match->permissions.nprim;  	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);  	if (!*perms) @@ -2678,13 +2758,13 @@ int security_get_permissions(char *class, char ***perms, int *nperms)  	if (match->comdatum) {  		rc = hashtab_map(match->comdatum->permissions.table,  				get_permissions_callback, *perms); -		if (rc < 0) +		if (rc)  			goto err;  	}  	rc = hashtab_map(match->permissions.table, get_permissions_callback,  			*perms); -	if (rc < 0) +	if (rc)  		goto err;  out: @@ -2774,7 +2854,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)  	case AUDIT_SUBJ_CLR:  	case AUDIT_OBJ_LEV_LOW:  	case AUDIT_OBJ_LEV_HIGH: -		/* we do not allow a range, indicated by the presense of '-' */ +		/* we do not allow a range, indicated by the presence of '-' */  		if (strchr(rulestr, '-'))  			return -EINVAL;  		break; @@ -2796,36 +2876,39 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)  	switch (field) {  	case AUDIT_SUBJ_USER:  	case AUDIT_OBJ_USER: +		rc = -EINVAL;  		userdatum = hashtab_search(policydb.p_users.table, rulestr);  		if (!userdatum) -			rc = -EINVAL; -		else -			tmprule->au_ctxt.user = userdatum->value; +			goto out; +		tmprule->au_ctxt.user = userdatum->value;  		break;  	case AUDIT_SUBJ_ROLE:  	case AUDIT_OBJ_ROLE: +		rc = -EINVAL;  		roledatum = hashtab_search(policydb.p_roles.table, rulestr);  		if (!roledatum) -			rc = -EINVAL; -		else -			tmprule->au_ctxt.role = roledatum->value; +			goto out; +		tmprule->au_ctxt.role = roledatum->value;  		break;  	case AUDIT_SUBJ_TYPE:  	case AUDIT_OBJ_TYPE: +		rc = -EINVAL;  		typedatum = hashtab_search(policydb.p_types.table, rulestr);  		if (!typedatum) -			rc = -EINVAL; -		else -			tmprule->au_ctxt.type = typedatum->value; +			goto out; +		tmprule->au_ctxt.type = typedatum->value;  		break;  	case AUDIT_SUBJ_SEN:  	case AUDIT_SUBJ_CLR:  	case AUDIT_OBJ_LEV_LOW:  	case AUDIT_OBJ_LEV_HIGH:  		rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); +		if (rc) +			goto out;  		break;  	} - +	rc = 0; +out:  	read_unlock(&policy_rwlock);  	if (rc) { @@ -2871,25 +2954,21 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,  	struct selinux_audit_rule *rule = vrule;  	int match = 0; -	if (!rule) { -		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, -			  "selinux_audit_rule_match: missing rule\n"); +	if (unlikely(!rule)) { +		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");  		return -ENOENT;  	}  	read_lock(&policy_rwlock);  	if (rule->au_seqno < latest_granting) { -		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, -			  "selinux_audit_rule_match: stale rule\n");  		match = -ESTALE;  		goto out;  	}  	ctxt = sidtab_search(&sidtab, sid); -	if (!ctxt) { -		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, -			  "selinux_audit_rule_match: unrecognized SID %d\n", +	if (unlikely(!ctxt)) { +		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",  			  sid);  		match = -ENOENT;  		goto out; @@ -2977,8 +3056,7 @@ out:  static int (*aurule_callback)(void) = audit_update_lsm_rules; -static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, -			       u16 class, u32 perms, u32 *retained) +static int aurule_avc_callback(u32 event)  {  	int err = 0; @@ -2991,8 +3069,7 @@ static int __init aurule_init(void)  {  	int err; -	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, -			       SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); +	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);  	if (err)  		panic("avc_add_callback() failed, error %d\n", err); @@ -3040,7 +3117,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,   * Description:   * Convert the given NetLabel security attributes in @secattr into a   * SELinux SID.  If the @secattr field does not contain a full SELinux - * SID/context then use SECINITSID_NETMSG as the foundation.  If possibile the + * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the   * 'cache' field of @secattr is set and the CACHE flag is set; this is to   * allow the @secattr to be used by NetLabel to cache the secattr to SID   * conversion for future lookups.  Returns zero on success, negative values on @@ -3050,7 +3127,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,  int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,  				   u32 *sid)  { -	int rc = -EIDRM; +	int rc;  	struct context *ctx;  	struct context ctx_new; @@ -3061,16 +3138,15 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,  	read_lock(&policy_rwlock); -	if (secattr->flags & NETLBL_SECATTR_CACHE) { +	if (secattr->flags & NETLBL_SECATTR_CACHE)  		*sid = *(u32 *)secattr->cache->data; -		rc = 0; -	} else if (secattr->flags & NETLBL_SECATTR_SECID) { +	else if (secattr->flags & NETLBL_SECATTR_SECID)  		*sid = secattr->attr.secid; -		rc = 0; -	} else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { +	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { +		rc = -EIDRM;  		ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);  		if (ctx == NULL) -			goto netlbl_secattr_to_sid_return; +			goto out;  		context_init(&ctx_new);  		ctx_new.user = ctx->user; @@ -3078,34 +3154,35 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,  		ctx_new.type = ctx->type;  		mls_import_netlbl_lvl(&ctx_new, secattr);  		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { -			if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, -						  secattr->attr.mls.cat) != 0) -				goto netlbl_secattr_to_sid_return; +			rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat, +						   secattr->attr.mls.cat); +			if (rc) +				goto out;  			memcpy(&ctx_new.range.level[1].cat,  			       &ctx_new.range.level[0].cat,  			       sizeof(ctx_new.range.level[0].cat));  		} -		if (mls_context_isvalid(&policydb, &ctx_new) != 1) -			goto netlbl_secattr_to_sid_return_cleanup; +		rc = -EIDRM; +		if (!mls_context_isvalid(&policydb, &ctx_new)) +			goto out_free;  		rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); -		if (rc != 0) -			goto netlbl_secattr_to_sid_return_cleanup; +		if (rc) +			goto out_free;  		security_netlbl_cache_add(secattr, *sid);  		ebitmap_destroy(&ctx_new.range.level[0].cat); -	} else { +	} else  		*sid = SECSID_NULL; -		rc = 0; -	} -netlbl_secattr_to_sid_return:  	read_unlock(&policy_rwlock); -	return rc; -netlbl_secattr_to_sid_return_cleanup: +	return 0; +out_free:  	ebitmap_destroy(&ctx_new.range.level[0].cat); -	goto netlbl_secattr_to_sid_return; +out: +	read_unlock(&policy_rwlock); +	return rc;  }  /** @@ -3127,28 +3204,23 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)  		return 0;  	read_lock(&policy_rwlock); + +	rc = -ENOENT;  	ctx = sidtab_search(&sidtab, sid); -	if (ctx == NULL) { -		rc = -ENOENT; -		goto netlbl_sid_to_secattr_failure; -	} -	secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], +	if (ctx == NULL) +		goto out; + +	rc = -ENOMEM; +	secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1),  				  GFP_ATOMIC); -	if (secattr->domain == NULL) { -		rc = -ENOMEM; -		goto netlbl_sid_to_secattr_failure; -	} +	if (secattr->domain == NULL) +		goto out; +  	secattr->attr.secid = sid;  	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;  	mls_export_netlbl_lvl(ctx, secattr);  	rc = mls_export_netlbl_cat(ctx, secattr); -	if (rc != 0) -		goto netlbl_sid_to_secattr_failure; -	read_unlock(&policy_rwlock); - -	return 0; - -netlbl_sid_to_secattr_failure: +out:  	read_unlock(&policy_rwlock);  	return rc;  } @@ -3160,7 +3232,7 @@ netlbl_sid_to_secattr_failure:   * @len: length of data in bytes   *   */ -int security_read_policy(void **data, ssize_t *len) +int security_read_policy(void **data, size_t *len)  {  	int rc;  	struct policy_file fp; diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index e817989764c..5840a35155f 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -147,6 +147,17 @@ out:  	return rc;  } +static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc) +{ +	BUG_ON(loc >= SIDTAB_CACHE_LEN); + +	while (loc > 0) { +		s->cache[loc] = s->cache[loc - 1]; +		loc--; +	} +	s->cache[0] = n; +} +  static inline u32 sidtab_search_context(struct sidtab *s,  						  struct context *context)  { @@ -156,14 +167,33 @@ static inline u32 sidtab_search_context(struct sidtab *s,  	for (i = 0; i < SIDTAB_SIZE; i++) {  		cur = s->htable[i];  		while (cur) { -			if (context_cmp(&cur->context, context)) +			if (context_cmp(&cur->context, context)) { +				sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1);  				return cur->sid; +			}  			cur = cur->next;  		}  	}  	return 0;  } +static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context) +{ +	int i; +	struct sidtab_node *node; + +	for (i = 0; i < SIDTAB_CACHE_LEN; i++) { +		node = s->cache[i]; +		if (unlikely(!node)) +			return 0; +		if (context_cmp(&node->context, context)) { +			sidtab_update_cache(s, node, i); +			return node->sid; +		} +	} +	return 0; +} +  int sidtab_context_to_sid(struct sidtab *s,  			  struct context *context,  			  u32 *out_sid) @@ -174,7 +204,9 @@ int sidtab_context_to_sid(struct sidtab *s,  	*out_sid = SECSID_NULL; -	sid = sidtab_search_context(s, context); +	sid  = sidtab_search_cache(s, context); +	if (!sid) +		sid = sidtab_search_context(s, context);  	if (!sid) {  		spin_lock_irqsave(&s->lock, flags);  		/* Rescan now that we hold the lock. */ @@ -259,12 +291,15 @@ void sidtab_destroy(struct sidtab *s)  void sidtab_set(struct sidtab *dst, struct sidtab *src)  {  	unsigned long flags; +	int i;  	spin_lock_irqsave(&src->lock, flags);  	dst->htable = src->htable;  	dst->nel = src->nel;  	dst->next_sid = src->next_sid;  	dst->shutdown = 0; +	for (i = 0; i < SIDTAB_CACHE_LEN; i++) +		dst->cache[i] = NULL;  	spin_unlock_irqrestore(&src->lock, flags);  } diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index 64ea5b1cdea..84dc154d938 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h @@ -26,6 +26,8 @@ struct sidtab {  	unsigned int nel;	/* number of elements */  	unsigned int next_sid;	/* next SID to allocate */  	unsigned char shutdown; +#define SIDTAB_CACHE_LEN	3 +	struct sidtab_node *cache[SIDTAB_CACHE_LEN];  	spinlock_t lock;  };  | 
